diff --git a/DEPS b/DEPS
index b53c722..213552df3 100644
--- a/DEPS
+++ b/DEPS
@@ -40,19 +40,19 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '9d7e57d509149dd2fcb3ba73ea8f4cdce11f84bd',
+  'skia_revision': '84c5435bcf8722f38e60f943b9de50c162e609ed',
   # 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': '255b03c11f25b8ddd746a0220dbcbc5c44843e28',
+  'v8_revision': '65e6f5fcbbceb1e02b9d322c4031e00696a0991a',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
-  'swarming_revision': '42721e128da760b345ab60d7cf34e300269112d7',
+  'swarming_revision': '72b6a2dc604673b84794937cb3da3fd755ccc4cd',
   # 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': 'a42a4e5ebfff75ef865a9d5623f1ff5dbf1539b2',
+  'angle_revision': '77d4d4da902464aeffcbaa7ade5b42c2012d63ee',
   # 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.
@@ -64,7 +64,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '31f7e4bb502e617a54da04a7600e8be7e2b62756',
+  'pdfium_revision': '304eefb58759e56be3fb357c78204accd4fa98fc',
   # 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.
@@ -72,7 +72,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
-  'boringssl_revision': 'ae9f0616c58bddcbe7a6d80d29d796bee9aaff2e',
+  'boringssl_revision': 'e3bb51cb2360fca5b87d559fc263b2763bd14739',
   # 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.
@@ -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': 'eebaedf9bcacd089d8561842ce75b64ebf71a26b',
+  'catapult_revision': '021853793c96f0b0fecadf76d38928f00220262b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -172,7 +172,7 @@
     Var('chromium_git') + '/external/gyp.git' + '@' + 'd61a9397e668fa9843c4aa7da9e79460fe590bfb',
 
   'src/tools/swarming_client':
-    Var('chromium_git') + '/external/swarming.client.git' + '@' +  Var('swarming_revision'),
+    Var('chromium_git') + '/infra/luci/client-py.git' + '@' +  Var('swarming_revision'),
 
   'src/v8':
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
@@ -516,7 +516,7 @@
       Var('chromium_git') + '/external/github.com/GoogleChrome/custom-tabs-client.git' + '@' + 'cff061038b852d647f7044d828a9df78aa135f38',
 
     'src/third_party/gvr-android-sdk/src':
-      Var('chromium_git') + '/external/github.com/googlevr/gvr-android-sdk.git' + '@' + 'a27f768b13682189c23eed69656319db5ef7cbfc',
+      Var('chromium_git') + '/external/github.com/googlevr/gvr-android-sdk.git' + '@' + 'ee5cb1c6138d0be57e82ddafc1b54d7d3e3e5560',
   },
 }
 
@@ -1190,18 +1190,6 @@
       ],
     },
     {
-      'name': 'gvr_common_aar',
-      'pattern': '\\.sha1',
-    'action': [   'python',
-                  'src/third_party/depot_tools/download_from_google_storage.py',
-                  '--no_resume',
-                  '--platform=linux*',
-                  '--no_auth',
-                  '--bucket', 'chromium-gvr-static-shim',
-                  '-s', 'src/third_party/gvr-android-sdk/common_library.aar.sha1',
-      ],
-    },
-    {
       'name': 'vr_controller_test_api',
       'pattern': '\\.sha1',
     'action': [   'python',
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn
index e3896eb0..6267dbe 100644
--- a/android_webview/BUILD.gn
+++ b/android_webview/BUILD.gn
@@ -768,6 +768,8 @@
     "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/AwAutofillManager.java",
+    "java/src/org/chromium/android_webview/AwAutofillProvider.java",
     "java/src/org/chromium/android_webview/AwBrowserContext.java",
     "java/src/org/chromium/android_webview/AwBrowserProcess.java",
     "java/src/org/chromium/android_webview/AwContentVideoViewEmbedder.java",
diff --git a/android_webview/browser/aw_permission_manager.cc b/android_webview/browser/aw_permission_manager.cc
index deda4e2..f4336f0 100644
--- a/android_webview/browser/aw_permission_manager.cc
+++ b/android_webview/browser/aw_permission_manager.cc
@@ -326,6 +326,7 @@
       case PermissionType::BACKGROUND_SYNC:
       case PermissionType::SENSORS:
       case PermissionType::FLASH:
+      case PermissionType::ACCESSIBILITY_EVENTS:
         NOTIMPLEMENTED() << "RequestPermissions is not implemented for "
                          << static_cast<int>(permissions[i]);
         pending_request_raw->SetPermissionStatus(permissions[i],
@@ -465,6 +466,7 @@
       case PermissionType::BACKGROUND_SYNC:
       case PermissionType::SENSORS:
       case PermissionType::FLASH:
+      case PermissionType::ACCESSIBILITY_EVENTS:
         NOTIMPLEMENTED() << "CancelPermission not implemented for "
                          << static_cast<int>(permission);
         break;
diff --git a/android_webview/browser/deferred_gpu_command_service.cc b/android_webview/browser/deferred_gpu_command_service.cc
index 2873d8c..66aaa6313 100644
--- a/android_webview/browser/deferred_gpu_command_service.cc
+++ b/android_webview/browser/deferred_gpu_command_service.cc
@@ -11,12 +11,16 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/synchronization/lock.h"
 #include "base/trace_event/trace_event.h"
+#include "content/public/browser/gpu_data_manager.h"
 #include "content/public/browser/gpu_utils.h"
 #include "content/public/common/content_switches.h"
 #include "gpu/command_buffer/service/gpu_preferences.h"
 #include "gpu/command_buffer/service/gpu_switches.h"
 #include "gpu/command_buffer/service/sync_point_manager.h"
+#include "gpu/config/gpu_info.h"
 #include "gpu/config/gpu_switches.h"
+#include "gpu/config/gpu_util.h"
+#include "ui/gl/gl_share_group.h"
 #include "ui/gl/gl_switches.h"
 
 namespace android_webview {
@@ -57,8 +61,15 @@
 
 // static
 void DeferredGpuCommandService::SetInstance() {
-  if (!g_service.Get().get())
-    g_service.Get() = new DeferredGpuCommandService;
+  if (!g_service.Get().get()) {
+    // TODO(zmo): Collect GPU info here instead.
+    gpu::GPUInfo gpu_info =
+        content::GpuDataManager::GetInstance()->GetGPUInfo();
+    DCHECK(base::CommandLine::InitializedForCurrentProcess());
+    gpu::GpuFeatureInfo gpu_feature_info = gpu::GetGpuFeatureInfo(
+        gpu_info, *base::CommandLine::ForCurrentProcess());
+    g_service.Get() = new DeferredGpuCommandService(gpu_info, gpu_feature_info);
+  }
 }
 
 // static
@@ -67,10 +78,16 @@
   return g_service.Get().get();
 }
 
-DeferredGpuCommandService::DeferredGpuCommandService()
+DeferredGpuCommandService::DeferredGpuCommandService(
+    const gpu::GPUInfo& gpu_info,
+    const gpu::GpuFeatureInfo& gpu_feature_info)
     : gpu::InProcessCommandBuffer::Service(
-          content::GetGpuPreferencesFromCommandLine()),
-      sync_point_manager_(new gpu::SyncPointManager()) {}
+          content::GetGpuPreferencesFromCommandLine(),
+          nullptr,
+          nullptr,
+          gpu_feature_info),
+      sync_point_manager_(new gpu::SyncPointManager()),
+      gpu_info_(gpu_info) {}
 
 DeferredGpuCommandService::~DeferredGpuCommandService() {
   base::AutoLock lock(tasks_lock_);
diff --git a/android_webview/browser/deferred_gpu_command_service.h b/android_webview/browser/deferred_gpu_command_service.h
index 20417222..cd8e295 100644
--- a/android_webview/browser/deferred_gpu_command_service.h
+++ b/android_webview/browser/deferred_gpu_command_service.h
@@ -16,9 +16,11 @@
 #include "base/memory/ref_counted.h"
 #include "base/threading/thread_local.h"
 #include "base/time/time.h"
+#include "gpu/config/gpu_info.h"
 #include "gpu/ipc/in_process_command_buffer.h"
 
 namespace gpu {
+struct GpuFeatureInfo;
 class SyncPointManager;
 }
 
@@ -62,6 +64,8 @@
   void Release() const override;
   bool BlockThreadOnWaitSyncToken() const override;
 
+  const gpu::GPUInfo& gpu_info() const { return gpu_info_; }
+
  protected:
   ~DeferredGpuCommandService() override;
   friend class base::RefCountedThreadSafe<DeferredGpuCommandService>;
@@ -70,7 +74,8 @@
   friend class ScopedAllowGL;
   static void RequestProcessGL(bool for_idle);
 
-  DeferredGpuCommandService();
+  DeferredGpuCommandService(const gpu::GPUInfo& gpu_info,
+                            const gpu::GpuFeatureInfo& gpu_feature_info);
   size_t IdleQueueSize();
 
   base::Lock tasks_lock_;
@@ -78,6 +83,7 @@
   std::queue<std::pair<base::Time, base::Closure> > idle_tasks_;
 
   std::unique_ptr<gpu::SyncPointManager> sync_point_manager_;
+  gpu::GPUInfo gpu_info_;
   DISALLOW_COPY_AND_ASSIGN(DeferredGpuCommandService);
 };
 
diff --git a/android_webview/glue/BUILD.gn b/android_webview/glue/BUILD.gn
index d2218ec..a289878 100644
--- a/android_webview/glue/BUILD.gn
+++ b/android_webview/glue/BUILD.gn
@@ -46,6 +46,7 @@
     "java/src/com/android/webview/chromium/WebMessagePortAdapter.java",
     "java/src/com/android/webview/chromium/WebStorageAdapter.java",
     "java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java",
+    "java/src/com/android/webview/chromium/WebViewChromiumFactoryProviderForO.java",
     "java/src/com/android/webview/chromium/WebViewChromium.java",
     "java/src/com/android/webview/chromium/WebViewContentsClientAdapter.java",
     "java/src/com/android/webview/chromium/WebViewDatabaseAdapter.java",
diff --git a/android_webview/glue/glue.gni b/android_webview/glue/glue.gni
index cdc293d4..0a3ce579 100644
--- a/android_webview/glue/glue.gni
+++ b/android_webview/glue/glue.gni
@@ -15,3 +15,7 @@
   "//net/android:net_java",
   "//ui/android:ui_java",
 ]
+
+# Omit downstream *ForO classes.
+# TODO(paulmiller): Remove this after removing those downstream classes.
+unpublished_apis_upstream = true
diff --git a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromium.java b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromium.java
index d250bc7..9e18c6b8 100644
--- a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromium.java
+++ b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromium.java
@@ -24,6 +24,7 @@
 import android.os.Message;
 import android.print.PrintDocumentAdapter;
 import android.util.Log;
+import android.util.SparseArray;
 import android.view.DragEvent;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
@@ -33,8 +34,10 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeProvider;
+import android.view.autofill.AutofillValue;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
+import android.view.textclassifier.TextClassifier;
 import android.webkit.DownloadListener;
 import android.webkit.FindActionModeCallback;
 import android.webkit.ValueCallback;
@@ -55,6 +58,7 @@
 import org.chromium.android_webview.AwPrintDocumentAdapter;
 import org.chromium.android_webview.AwSettings;
 import org.chromium.android_webview.ResourcesContextWrapperFactory;
+import org.chromium.android_webview.renderer_priority.RendererPriority;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.annotations.SuppressFBWarnings;
 import org.chromium.components.autofill.AutofillProvider;
@@ -1487,19 +1491,79 @@
     @Override
     public void setRendererPriorityPolicy(
             int rendererRequestedPriority, boolean waivedWhenNotVisible) {
-        // TODO(paulmiller): Unfork O APIs
+        @RendererPriority
+        int awRendererRequestedPriority;
+        switch (rendererRequestedPriority) {
+            case WebView.RENDERER_PRIORITY_WAIVED:
+                awRendererRequestedPriority = RendererPriority.WAIVED;
+                break;
+            case WebView.RENDERER_PRIORITY_BOUND:
+                awRendererRequestedPriority = RendererPriority.LOW;
+                break;
+            default:
+            case WebView.RENDERER_PRIORITY_IMPORTANT:
+                awRendererRequestedPriority = RendererPriority.HIGH;
+                break;
+        }
+        mAwContents.setRendererPriorityPolicy(awRendererRequestedPriority, waivedWhenNotVisible);
     }
 
     @Override
     public int getRendererRequestedPriority() {
-        // TODO(paulmiller): Unfork O APIs
-        return 0;
+        @RendererPriority
+        final int awRendererRequestedPriority = mAwContents.getRendererRequestedPriority();
+        switch (awRendererRequestedPriority) {
+            case RendererPriority.WAIVED:
+                return WebView.RENDERER_PRIORITY_WAIVED;
+            case RendererPriority.LOW:
+                return WebView.RENDERER_PRIORITY_BOUND;
+            default:
+            case RendererPriority.HIGH:
+                return WebView.RENDERER_PRIORITY_IMPORTANT;
+        }
     }
 
     @Override
     public boolean getRendererPriorityWaivedWhenNotVisible() {
-        // TODO(paulmiller): Unfork O APIs
-        return false;
+        return mAwContents.getRendererPriorityWaivedWhenNotVisible();
+    }
+
+    @Override
+    public void setTextClassifier(TextClassifier textClassifier) {
+        mAwContents.setTextClassifier(textClassifier);
+    }
+
+    @Override
+    public TextClassifier getTextClassifier() {
+        return (TextClassifier) mAwContents.getTextClassifier();
+    }
+
+    public void autofill(final SparseArray<AutofillValue> values) {
+        mFactory.startYourEngines(false);
+        if (checkNeedsPost()) {
+            mFactory.runVoidTaskOnUiThreadBlocking(new Runnable() {
+                @Override
+                public void run() {
+                    autofill(values);
+                }
+            });
+        }
+        mAwContents.autofill(values);
+    }
+
+    @Override
+    public void onProvideAutofillVirtualStructure(final ViewStructure structure, final int flags) {
+        mFactory.startYourEngines(false);
+        if (checkNeedsPost()) {
+            mFactory.runVoidTaskOnUiThreadBlocking(new Runnable() {
+                @Override
+                public void run() {
+                    onProvideAutofillVirtualStructure(structure, flags);
+                }
+            });
+            return;
+        }
+        mAwContents.onProvideAutoFillVirtualStructure(structure, flags);
     }
 
     // WebViewProvider glue methods ---------------------------------------------------------------
diff --git a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
index fd0b302..2c5777f 100644
--- a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
+++ b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
@@ -35,6 +35,7 @@
 
 import com.android.webview.chromium.WebViewDelegateFactory.WebViewDelegate;
 
+import org.chromium.android_webview.AwAutofillProvider;
 import org.chromium.android_webview.AwBrowserContext;
 import org.chromium.android_webview.AwBrowserProcess;
 import org.chromium.android_webview.AwContents;
@@ -67,6 +68,7 @@
 import org.chromium.base.library_loader.ProcessInitException;
 import org.chromium.components.autofill.AutofillProvider;
 import org.chromium.content.browser.input.LGEmailActionModeWorkaround;
+import org.chromium.content_public.browser.SmartSelectionToggle;
 import org.chromium.net.NetworkChangeNotifier;
 
 import java.io.File;
@@ -411,6 +413,7 @@
         PathService.override(PathService.DIR_MODULE, "/system/lib/");
         PathService.override(DIR_RESOURCE_PAKS_ANDROID, "/system/framework/webview/paks");
 
+        SmartSelectionToggle.setEnabled(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O);
         // Make sure that ResourceProvider is initialized before starting the browser process.
         final PackageInfo webViewPackageInfo = WebViewFactory.getLoadedPackageInfo();
         final String webViewPackageName = webViewPackageInfo.packageName;
@@ -723,13 +726,13 @@
         return mWebViewDelegate;
     }
 
-    // The method to support unreleased Android.
     WebViewContentsClientAdapter createWebViewContentsClientAdapter(WebView webView,
             Context context) {
         return new WebViewContentsClientAdapter(webView, context, mWebViewDelegate);
     }
 
     AutofillProvider createAutofillProvider(Context context, ViewGroup containerView) {
-        return null;
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return null;
+        return new AwAutofillProvider(context, containerView);
     }
 }
diff --git a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProviderForO.java b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProviderForO.java
new file mode 100644
index 0000000..6962de1
--- /dev/null
+++ b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProviderForO.java
@@ -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.
+
+package com.android.webview.chromium;
+
+class WebViewChromiumFactoryProviderForO extends WebViewChromiumFactoryProvider {
+    public static WebViewChromiumFactoryProvider create(android.webkit.WebViewDelegate delegate) {
+        return new WebViewChromiumFactoryProviderForO(delegate);
+    }
+
+    protected WebViewChromiumFactoryProviderForO(android.webkit.WebViewDelegate delegate) {
+        super(delegate);
+    }
+}
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 858c29a..56416ec 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
@@ -27,6 +27,7 @@
 import android.webkit.JsPromptResult;
 import android.webkit.JsResult;
 import android.webkit.PermissionRequest;
+import android.webkit.RenderProcessGoneDetail;
 import android.webkit.SslErrorHandler;
 import android.webkit.ValueCallback;
 import android.webkit.WebChromeClient;
@@ -1216,8 +1217,26 @@
     }
 
     @Override
-    public boolean onRenderProcessGone(AwRenderProcessGoneDetail detail) {
-        return false;
+    public boolean onRenderProcessGone(final AwRenderProcessGoneDetail detail) {
+        // WebViewClient.onRenderProcessGone was added in O.
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return false;
+
+        try {
+            TraceEvent.begin("WebViewContentsClientAdapter.onRenderProcessGone");
+            return mWebViewClient.onRenderProcessGone(mWebView, new RenderProcessGoneDetail() {
+                @Override
+                public boolean didCrash() {
+                    return detail.didCrash();
+                }
+
+                @Override
+                public int rendererPriorityAtExit() {
+                    return detail.rendererPriority();
+                }
+            });
+        } finally {
+            TraceEvent.end("WebViewContentsClientAdapter.onRenderProcessGone");
+        }
     }
 
     // TODO: Move to upstream.
diff --git a/android_webview/glue/java/src/com/android/webview/chromium/WebViewDelegateFactory.java b/android_webview/glue/java/src/com/android/webview/chromium/WebViewDelegateFactory.java
index 23ecf26..cb75912 100644
--- a/android_webview/glue/java/src/com/android/webview/chromium/WebViewDelegateFactory.java
+++ b/android_webview/glue/java/src/com/android/webview/chromium/WebViewDelegateFactory.java
@@ -204,7 +204,7 @@
 
         @Override
         public boolean isMultiProcessEnabled() {
-            throw new UnsupportedOperationException();
+            return mDelegate.isMultiProcessEnabled();
         }
     }
 
diff --git a/android_webview/gpu/aw_content_gpu_client.cc b/android_webview/gpu/aw_content_gpu_client.cc
index fcd3eec7..bd95297 100644
--- a/android_webview/gpu/aw_content_gpu_client.cc
+++ b/android_webview/gpu/aw_content_gpu_client.cc
@@ -7,8 +7,12 @@
 namespace android_webview {
 
 AwContentGpuClient::AwContentGpuClient(
-    const GetSyncPointManagerCallback& callback)
-    : sync_point_manager_callback_(callback) {}
+    const GetSyncPointManagerCallback& sync_point_manager_callback,
+    const GetGPUInfoCallback gpu_info_callback,
+    const GetGpuFeatureInfoCallback gpu_feature_info_callback)
+    : sync_point_manager_callback_(sync_point_manager_callback),
+      gpu_info_callback_(gpu_info_callback),
+      gpu_feature_info_callback_(gpu_feature_info_callback) {}
 
 AwContentGpuClient::~AwContentGpuClient() {}
 
@@ -16,4 +20,12 @@
   return sync_point_manager_callback_.Run();
 }
 
+const gpu::GPUInfo* AwContentGpuClient::GetGPUInfo() {
+  return &(gpu_info_callback_.Run());
+}
+
+const gpu::GpuFeatureInfo* AwContentGpuClient::GetGpuFeatureInfo() {
+  return &(gpu_feature_info_callback_.Run());
+}
+
 }  // namespace android_webview
diff --git a/android_webview/gpu/aw_content_gpu_client.h b/android_webview/gpu/aw_content_gpu_client.h
index 931b8a1..4004885 100644
--- a/android_webview/gpu/aw_content_gpu_client.h
+++ b/android_webview/gpu/aw_content_gpu_client.h
@@ -14,15 +14,25 @@
 class AwContentGpuClient : public content::ContentGpuClient {
  public:
   using GetSyncPointManagerCallback = base::Callback<gpu::SyncPointManager*()>;
+  using GetGPUInfoCallback = base::Callback<const gpu::GPUInfo&()>;
+  using GetGpuFeatureInfoCallback =
+      base::Callback<const gpu::GpuFeatureInfo&()>;
 
-  explicit AwContentGpuClient(const GetSyncPointManagerCallback& callback);
+  explicit AwContentGpuClient(
+      const GetSyncPointManagerCallback& sync_point_manager_callback,
+      const GetGPUInfoCallback gpu_info_callback,
+      const GetGpuFeatureInfoCallback gpu_feature_info_callback);
   ~AwContentGpuClient() override;
 
   // content::ContentGpuClient implementation.
   gpu::SyncPointManager* GetSyncPointManager() override;
+  const gpu::GPUInfo* GetGPUInfo() override;
+  const gpu::GpuFeatureInfo* GetGpuFeatureInfo() override;
 
  private:
   GetSyncPointManagerCallback sync_point_manager_callback_;
+  GetGPUInfoCallback gpu_info_callback_;
+  GetGpuFeatureInfoCallback gpu_feature_info_callback_;
   DISALLOW_COPY_AND_ASSIGN(AwContentGpuClient);
 };
 
diff --git a/android_webview/java/src/org/chromium/android_webview/AwAutofillManager.java b/android_webview/java/src/org/chromium/android_webview/AwAutofillManager.java
new file mode 100644
index 0000000..2aefc06d
--- /dev/null
+++ b/android_webview/java/src/org/chromium/android_webview/AwAutofillManager.java
@@ -0,0 +1,97 @@
+// 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.graphics.Rect;
+import android.view.View;
+import android.view.autofill.AutofillManager;
+import android.view.autofill.AutofillValue;
+
+import org.chromium.base.Log;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * The class to call Android's AutofillManager.
+ */
+// TODO(michaelbai): Extend this class to provide instrumentation test. http://crbug.com/717658.
+public class AwAutofillManager {
+    private static final String TAG = "AwAutofillManager";
+
+    private static class AutofillInputUIMonitor extends AutofillManager.AutofillCallback {
+        private WeakReference<AwAutofillManager> mManager;
+
+        public AutofillInputUIMonitor(AwAutofillManager manager) {
+            mManager = new WeakReference<AwAutofillManager>(manager);
+        }
+
+        @Override
+        public void onAutofillEvent(View view, int virtualId, int event) {
+            AwAutofillManager manager = mManager.get();
+            if (manager == null) return;
+            manager.mIsAutofillInputUIShowing = (event == EVENT_INPUT_SHOWN);
+        }
+    }
+
+    private AutofillManager mAutofillManager;
+    private boolean mIsAutofillInputUIShowing;
+    private AutofillInputUIMonitor mMonitor;
+
+    public AwAutofillManager(Context context) {
+        mAutofillManager = context.getSystemService(AutofillManager.class);
+        mMonitor = new AutofillInputUIMonitor(this);
+        mAutofillManager.registerCallback(mMonitor);
+    }
+
+    public void notifyVirtualValueChanged(View parent, int childId, AutofillValue value) {
+        if (isDestroyed()) return;
+        mAutofillManager.notifyValueChanged(parent, childId, value);
+    }
+
+    public void commit() {
+        if (isDestroyed()) return;
+        mAutofillManager.commit();
+    }
+
+    public void cancel() {
+        if (isDestroyed()) return;
+        mAutofillManager.cancel();
+    }
+
+    public void notifyVirtualViewEntered(View parent, int childId, Rect absBounds) {
+        if (isDestroyed()) return;
+        mAutofillManager.notifyViewEntered(parent, childId, absBounds);
+    }
+
+    public void notifyVirtualViewExited(View parent, int childId) {
+        if (isDestroyed()) return;
+        mAutofillManager.notifyViewExited(parent, childId);
+    }
+
+    public void requestAutofill(View parent, int virtualId, Rect absBounds) {
+        if (isDestroyed()) return;
+        mAutofillManager.requestAutofill(parent, virtualId, absBounds);
+    }
+
+    public boolean isAutofillInputUIShowing() {
+        if (isDestroyed()) return false;
+        return mIsAutofillInputUIShowing;
+    }
+
+    public void destroy() {
+        if (isDestroyed()) return;
+        mAutofillManager.unregisterCallback(mMonitor);
+        mAutofillManager = null;
+    }
+
+    private boolean isDestroyed() {
+        if (mAutofillManager == null) {
+            Log.w(TAG, "Application attempted to call on a destroyed AwAutofillManager",
+                    new Throwable());
+        }
+        return mAutofillManager == null;
+    }
+}
diff --git a/android_webview/java/src/org/chromium/android_webview/AwAutofillProvider.java b/android_webview/java/src/org/chromium/android_webview/AwAutofillProvider.java
new file mode 100644
index 0000000..cd70319c
--- /dev/null
+++ b/android_webview/java/src/org/chromium/android_webview/AwAutofillProvider.java
@@ -0,0 +1,378 @@
+// 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.graphics.Matrix;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.util.SparseArray;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewStructure;
+import android.view.autofill.AutofillValue;
+
+import org.chromium.base.ThreadUtils;
+import org.chromium.components.autofill.AutofillProvider;
+import org.chromium.components.autofill.FormData;
+import org.chromium.components.autofill.FormFieldData;
+import org.chromium.content_public.browser.WebContents;
+import org.chromium.ui.base.WindowAndroid;
+import org.chromium.ui.display.DisplayAndroid;
+
+/**
+ * This class uses Android autofill service to fill web form. All methods are
+ * supposed to be called in UI thread.
+ *
+ * This class doesn't have 1:1 mapping to native AutofillProviderAndroid and is
+ * same as how AwContents.java mapping to native AwContents, AwAutofillProvider
+ * is owned by AwContents.java and AutofillProviderAndroid is owned by native
+ * AwContents.
+ */
+public class AwAutofillProvider extends AutofillProvider {
+    private static class FocusField {
+        public final short fieldIndex;
+        public final Rect absBound;
+
+        public FocusField(short fieldIndex, Rect absBound) {
+            this.fieldIndex = fieldIndex;
+            this.absBound = absBound;
+        }
+    }
+    /**
+     * The class to wrap the request to framework.
+     *
+     * Though framework guarantees always giving us the autofill value of current
+     * session, we still want to verify this by using unique virtual id which is
+     * composed of sessionId and form field index, we don't use the request id
+     * which comes from renderer as session id because it is not unique.
+     */
+    private static class AutofillRequest {
+        private static final int INIT_ID = 1; // ID can't be 0 in Android.
+        private static int sSessionId = INIT_ID;
+        public final int sessionId;
+        private FormData mFormData;
+        private FocusField mFocusField;
+
+        public AutofillRequest(FormData formData, FocusField focus) {
+            sessionId = getNextClientId();
+            mFormData = formData;
+            mFocusField = focus;
+        }
+
+        public void fillViewStructure(ViewStructure structure) {
+            structure.setClassName(mFormData.mName);
+            structure.setWebDomain(mFormData.mHost);
+            int index = structure.addChildCount(mFormData.mFields.size());
+            short fieldIndex = 0;
+            for (FormFieldData field : mFormData.mFields) {
+                ViewStructure child = structure.newChild(index++);
+                int virtualId = toVirtualId(sessionId, fieldIndex++);
+                child.setAutofillId(structure.getAutofillId(), virtualId);
+                if (field.mAutocompleteAttr != null) {
+                    child.setAutofillHints(field.mAutocompleteAttr.split(" +"));
+                }
+                child.setHint(field.mPlaceholder);
+                child.setHtmlInfo(child.newHtmlInfoBuilder("input")
+                                          .addAttribute("name", field.mName)
+                                          .addAttribute("type", field.mType)
+                                          .build());
+                switch (field.getControlType()) {
+                    case FormFieldData.TYPE_LIST:
+                        child.setAutofillType(View.AUTOFILL_TYPE_LIST);
+                        child.setAutofillOptions(field.mOptionContents);
+                        int i = findIndex(field.mOptionValues, field.getValue());
+                        if (i != -1) {
+                            child.setAutofillValue(AutofillValue.forList(i));
+                        }
+                        break;
+                    case FormFieldData.TYPE_TOGGLE:
+                        child.setAutofillType(View.AUTOFILL_TYPE_TOGGLE);
+                        child.setAutofillValue(AutofillValue.forToggle(field.isChecked()));
+                        break;
+                    case FormFieldData.TYPE_TEXT:
+                        child.setAutofillType(View.AUTOFILL_TYPE_TEXT);
+                        child.setAutofillValue(AutofillValue.forText(field.getValue()));
+                        break;
+                    default:
+                        break;
+                }
+            }
+        }
+
+        public boolean autofill(final SparseArray<AutofillValue> values) {
+            for (int i = 0; i < values.size(); ++i) {
+                int id = values.keyAt(i);
+                if (toSessionId(id) != sessionId) return false;
+                AutofillValue value = values.get(id);
+                if (value == null) continue;
+                short index = toIndex(id);
+                if (index < 0 || index >= mFormData.mFields.size()) return false;
+                FormFieldData field = mFormData.mFields.get(index);
+                if (field == null) return false;
+                switch (field.getControlType()) {
+                    case FormFieldData.TYPE_LIST:
+                        int j = value.getListValue();
+                        if (j < 0 && j >= field.mOptionValues.length) continue;
+                        field.updateValue(field.mOptionValues[j]);
+                        break;
+                    case FormFieldData.TYPE_TOGGLE:
+                        field.setChecked(value.getToggleValue());
+                        break;
+                    case FormFieldData.TYPE_TEXT:
+                        field.updateValue((String) value.getTextValue());
+                        break;
+                    default:
+                        break;
+                }
+            }
+            return true;
+        }
+
+        public void setFocusField(FocusField focusField) {
+            mFocusField = focusField;
+        }
+
+        public FocusField getFocusField() {
+            return mFocusField;
+        }
+
+        public int getFieldCount() {
+            return mFormData.mFields.size();
+        }
+
+        public AutofillValue getFieldNewValue(int index) {
+            FormFieldData field = mFormData.mFields.get(index);
+            if (field == null) return null;
+            String value = field.getValue();
+            return AutofillValue.forText(value);
+        }
+
+        public int getVirtualId(short index) {
+            return toVirtualId(sessionId, index);
+        }
+
+        private static int findIndex(String[] values, String value) {
+            if (values != null && value != null) {
+                for (int i = 0; i < values.length; i++) {
+                    if (value.equals(values[i])) return i;
+                }
+            }
+            return -1;
+        }
+
+        private static int getNextClientId() {
+            ThreadUtils.assertOnUiThread();
+            if (sSessionId == 0xffff) sSessionId = INIT_ID;
+            return sSessionId++;
+        }
+
+        private static int toSessionId(int virtualId) {
+            return (virtualId & 0xffff0000) >> 16;
+        }
+
+        private static short toIndex(int virtualId) {
+            return (short) (virtualId & 0xffff);
+        }
+
+        private static int toVirtualId(int clientId, short index) {
+            return (clientId << 16) | index;
+        }
+    }
+
+    private AwAutofillManager mAutofillManager;
+    private ViewGroup mContainerView;
+    private WebContents mWebContents;
+
+    private AutofillRequest mRequest;
+    private long mNativeAutofillProvider;
+
+    public AwAutofillProvider(Context context, ViewGroup containerView) {
+        mAutofillManager = new AwAutofillManager(context);
+        mContainerView = containerView;
+    }
+
+    @Override
+    public void onContainerViewChanged(ViewGroup containerView) {
+        mContainerView = containerView;
+    }
+
+    @Override
+    public void onProvideAutoFillVirtualStructure(ViewStructure structure, int flags) {
+        // This method could be called for the session started by the native
+        // control outside of WebView, e.g. the URL bar, in this case, we simply
+        // return.
+        if (mRequest == null) return;
+        mRequest.fillViewStructure(structure);
+    }
+
+    @Override
+    public void autofill(final SparseArray<AutofillValue> values) {
+        if (mNativeAutofillProvider != 0 && mRequest.autofill((values))) {
+            autofill(mNativeAutofillProvider, mRequest.mFormData);
+        }
+    }
+
+    @Override
+    public boolean shouldQueryAutofillSuggestion() {
+        return mRequest != null && mRequest.getFocusField() != null
+                && !mAutofillManager.isAutofillInputUIShowing();
+    }
+
+    @Override
+    public void queryAutofillSuggestion() {
+        if (shouldQueryAutofillSuggestion()) {
+            FocusField focusField = mRequest.getFocusField();
+            mAutofillManager.requestAutofill(mContainerView,
+                    mRequest.getVirtualId(focusField.fieldIndex), focusField.absBound);
+        }
+    }
+
+    @Override
+    public void startAutofillSession(
+            FormData formData, int focus, float x, float y, float width, float height) {
+        // Check focusField inside short value?
+        // Autofill Manager might have session that wasn't started by WebView,
+        // we just always cancel existing session here.
+        mAutofillManager.cancel();
+        Rect absBound = transformToWindowBounds(new RectF(x, y, x + width, y + height));
+        mRequest = new AutofillRequest(formData, new FocusField((short) focus, absBound));
+        int virtualId = mRequest.getVirtualId((short) focus);
+        mAutofillManager.notifyVirtualViewEntered(mContainerView, virtualId, absBound);
+    }
+
+    @Override
+    public void onTextFieldDidChange(int index, float x, float y, float width, float height) {
+        // Check index inside short value?
+        if (mRequest == null) return;
+
+        short sIndex = (short) index;
+        FocusField focusField = mRequest.getFocusField();
+        if (focusField == null || sIndex != focusField.fieldIndex) {
+            onFocusChanged(true, index, x, y, width, height);
+        } else {
+            // Currently there is no api to notify both value and position
+            // change, before the API is availabe, we still need to call
+            // notifyVirtualViewEntered() to tell current coordinates because
+            // the position could be changed.
+            int virtualId = mRequest.getVirtualId(sIndex);
+            Rect absBound = transformToWindowBounds(new RectF(x, y, x + width, y + height));
+            mAutofillManager.notifyVirtualViewExited(mContainerView, virtualId);
+            mAutofillManager.notifyVirtualViewEntered(mContainerView, virtualId, absBound);
+            // Update focus field position.
+            mRequest.setFocusField(new FocusField(focusField.fieldIndex, absBound));
+        }
+        notifyVirtualValueChanged(index);
+    }
+
+    private void notifyVirtualValueChanged(int index) {
+        AutofillValue autofillValue = mRequest.getFieldNewValue(index);
+        mAutofillManager.notifyVirtualValueChanged(
+                mContainerView, mRequest.getVirtualId((short) index), autofillValue);
+    }
+
+    @Override
+    public void onWillSubmitForm() {
+        // The changes could be missing, like those made by Javascript, we'd better to notify
+        // AutofillManager current values. also see crbug.com/353001 and crbug.com/732856.
+        notifyFormValues();
+        mAutofillManager.commit();
+        mRequest = null;
+    }
+
+    @Override
+    public void onFocusChanged(
+            boolean focusOnForm, int focusField, float x, float y, float width, float height) {
+        // Check focusField inside short value?
+        // FocusNoLongerOnForm is called after form submitted.
+        if (mRequest == null) return;
+        FocusField prev = mRequest.getFocusField();
+        if (focusOnForm) {
+            Rect absBound = transformToWindowBounds(new RectF(x, y, x + width, y + height));
+            if (prev != null && prev.fieldIndex == focusField && absBound.equals(prev.absBound)) {
+                return;
+            }
+
+            // Notify focus changed.
+            if (prev != null) {
+                mAutofillManager.notifyVirtualViewExited(
+                        mContainerView, mRequest.getVirtualId(prev.fieldIndex));
+            }
+
+            mAutofillManager.notifyVirtualViewEntered(
+                    mContainerView, mRequest.getVirtualId((short) focusField), absBound);
+            // The focus field value might not sync with platform's
+            // AutofillManager, just notify it value changed.
+            notifyVirtualValueChanged(focusField);
+            mRequest.setFocusField(new FocusField((short) focusField, absBound));
+        } else {
+            if (prev == null) return;
+            // Notify focus changed.
+            mAutofillManager.notifyVirtualViewExited(
+                    mContainerView, mRequest.getVirtualId(prev.fieldIndex));
+            mRequest.setFocusField(null);
+        }
+    }
+
+    @Override
+    protected void reset() {
+        mAutofillManager.cancel();
+        mRequest = null;
+    }
+
+    @Override
+    protected void setNativeAutofillProvider(long nativeAutofillProvider) {
+        if (nativeAutofillProvider == mNativeAutofillProvider) return;
+        mNativeAutofillProvider = nativeAutofillProvider;
+        // Setting the mNativeAutofillProvider to 0 may occur as a
+        // result of WebView.destroy, or because a WebView has been
+        // gc'ed. In the former case we can go ahead and clean up the
+        // frameworks autofill manager, but in the latter case the
+        // binder connection has already been dropped in a framework
+        // finalizer, and so the methods we call will throw. It's not
+        // possible to know which case we're in, so just catch and
+        // ignore the exception.
+        try {
+            reset();
+            if (nativeAutofillProvider == 0) {
+                mAutofillManager.destroy();
+            }
+        } catch (IllegalStateException e) {
+        }
+    }
+
+    @Override
+    public void setWebContents(WebContents webContents) {
+        if (webContents == mWebContents) return;
+        mWebContents = webContents;
+        reset();
+    }
+
+    @Override
+    protected void onDidFillAutofillFormData() {
+        notifyFormValues();
+    }
+
+    private void notifyFormValues() {
+        if (mRequest == null) return;
+        for (int i = 0; i < mRequest.getFieldCount(); ++i) notifyVirtualValueChanged(i);
+    }
+
+    private Rect transformToWindowBounds(RectF rect) {
+        // Convert bounds to device pixel.
+        WindowAndroid windowAndroid = mWebContents.getTopLevelNativeWindow();
+        DisplayAndroid displayAndroid = windowAndroid.getDisplay();
+        float dipScale = displayAndroid.getDipScale();
+        RectF bounds = new RectF(rect);
+        Matrix matrix = new Matrix();
+        matrix.setScale(dipScale, dipScale);
+        int[] location = new int[2];
+        mContainerView.getLocationOnScreen(location);
+        matrix.postTranslate(location[0], location[1]);
+        matrix.mapRect(bounds);
+        return new Rect(
+                (int) bounds.left, (int) bounds.top, (int) bounds.right, (int) bounds.bottom);
+    }
+}
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 6090015..62abbdd8 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContents.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -41,8 +41,10 @@
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeProvider;
 import android.view.animation.AnimationUtils;
+import android.view.autofill.AutofillValue;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
+import android.view.textclassifier.TextClassifier;
 import android.webkit.JavascriptInterface;
 import android.webkit.ValueCallback;
 
@@ -1047,7 +1049,7 @@
      */
     private void setNewAwContents(long newAwContentsPtr) {
         // Move the text classifier to the new ContentViewCore.
-        Object textClassifier =
+        TextClassifier textClassifier =
                 mContentViewCore == null ? null : mContentViewCore.getCustomTextClassifier();
 
         if (mNativeAwContents != 0) {
@@ -2325,7 +2327,7 @@
         }
     }
 
-    public void autofill(final SparseArray<Object> values) {
+    public void autofill(final SparseArray<AutofillValue> values) {
         if (mAutofillProvider != null) {
             mAutofillProvider.autofill(values);
         }
@@ -2729,14 +2731,12 @@
         updateChildProcessImportance();
     }
 
-    // TODO(timav): Use |TextClassifier| instead of |Object| after we switch to Android SDK 26.
-    public void setTextClassifier(Object textClassifier) {
+    public void setTextClassifier(TextClassifier textClassifier) {
         assert mContentViewCore != null;
         mContentViewCore.setTextClassifier(textClassifier);
     }
 
-    // TODO(timav): Use |TextClassifier| instead of |Object| after we switch to Android SDK 26.
-    public Object getTextClassifier() {
+    public TextClassifier getTextClassifier() {
         assert mContentViewCore != null;
         return mContentViewCore.getTextClassifier();
     }
diff --git a/android_webview/lib/aw_main_delegate.cc b/android_webview/lib/aw_main_delegate.cc
index 60f5efd1..04cf4035 100644
--- a/android_webview/lib/aw_main_delegate.cc
+++ b/android_webview/lib/aw_main_delegate.cc
@@ -255,11 +255,22 @@
   DCHECK(DeferredGpuCommandService::GetInstance());
   return DeferredGpuCommandService::GetInstance()->sync_point_manager();
 }
+
+const gpu::GPUInfo& GetGPUInfo() {
+  DCHECK(DeferredGpuCommandService::GetInstance());
+  return DeferredGpuCommandService::GetInstance()->gpu_info();
+}
+
+const gpu::GpuFeatureInfo& GetGpuFeatureInfo() {
+  DCHECK(DeferredGpuCommandService::GetInstance());
+  return DeferredGpuCommandService::GetInstance()->gpu_feature_info();
+}
 }  // namespace
 
 content::ContentGpuClient* AwMainDelegate::CreateContentGpuClient() {
-  content_gpu_client_.reset(
-      new AwContentGpuClient(base::Bind(&GetSyncPointManager)));
+  content_gpu_client_.reset(new AwContentGpuClient(
+      base::Bind(&GetSyncPointManager), base::Bind(&GetGPUInfo),
+      base::Bind(&GetGpuFeatureInfo)));
   return content_gpu_client_.get();
 }
 
diff --git a/ash/accelerators/accelerator_controller.cc b/ash/accelerators/accelerator_controller.cc
index 9501950..2abfc9c 100644
--- a/ash/accelerators/accelerator_controller.cc
+++ b/ash/accelerators/accelerator_controller.cc
@@ -154,16 +154,18 @@
                                            int new_shortcut_id) {
   const base::string16 message =
       GetNotificationText(message_id, old_shortcut_id, new_shortcut_id);
-  std::unique_ptr<Notification> notification(new Notification(
-      message_center::NOTIFICATION_TYPE_SIMPLE, notification_id,
-      base::string16(), message,
-      Shell::Get()->shell_delegate()->GetDeprecatedAcceleratorImage(),
-      base::string16(), GURL(),
-      message_center::NotifierId(
-          message_center::NotifierId::SYSTEM_COMPONENT,
-          system_notifier::kNotifierDeprecatedAccelerator),
-      message_center::RichNotificationData(),
-      new DeprecatedAcceleratorNotificationDelegate));
+  std::unique_ptr<Notification> notification =
+      system_notifier::CreateSystemNotification(
+          message_center::NOTIFICATION_TYPE_SIMPLE, notification_id,
+          l10n_util::GetStringUTF16(IDS_DEPRECATED_SHORTCUT_TITLE), message,
+          Shell::Get()->shell_delegate()->GetDeprecatedAcceleratorImage(),
+          base::string16(), GURL(),
+          message_center::NotifierId(
+              message_center::NotifierId::SYSTEM_COMPONENT,
+              system_notifier::kNotifierDeprecatedAccelerator),
+          message_center::RichNotificationData(),
+          new DeprecatedAcceleratorNotificationDelegate,
+          kNotificationSettingsIcon, SystemNotificationWarningLevel::NORMAL);
   message_center::MessageCenter::Get()->AddNotification(
       std::move(notification));
 }
diff --git a/ash/accelerators/accelerator_controller_unittest.cc b/ash/accelerators/accelerator_controller_unittest.cc
index bc22999..5ef7204 100644
--- a/ash/accelerators/accelerator_controller_unittest.cc
+++ b/ash/accelerators/accelerator_controller_unittest.cc
@@ -795,8 +795,8 @@
       ui::Accelerator(ui::VKEY_T, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN)));
 
   // Show task manager
-  EXPECT_TRUE(
-      ProcessInController(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_SHIFT_DOWN)));
+  EXPECT_TRUE(ProcessInController(
+      ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_COMMAND_DOWN)));
 
   // Open file manager
   EXPECT_TRUE(ProcessInController(
@@ -808,6 +808,9 @@
   // effect of locking the screen.
   EXPECT_TRUE(
       ProcessInController(ui::Accelerator(ui::VKEY_L, ui::EF_COMMAND_DOWN)));
+
+  message_center::MessageCenter::Get()->RemoveAllNotifications(
+      false /* by_user */, message_center::MessageCenter::RemoveType::ALL);
 }
 
 TEST_F(AcceleratorControllerTest, GlobalAcceleratorsToggleAppList) {
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index adecc70..bfd1b9e 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -450,7 +450,7 @@
       <message name="IDS_ASH_VOICE_INTERACTION_LOCALE_UNSUPPORTED_TOAST_MESSAGE" desc="Message content on the toast that appears when the voice interaction shortcut is pressed but the locale is unsupported.">
         The Google Assistant doesn’t speak this language.
       </message>
-      <message name="IDS_ASH_VOICE_INTERACTION_SECONDARY_USER_TOAST_MESSAGE" desc="Message content on the toast that appears when the voice interaction shortcut is pressed but the locale is unsupported.">
+      <message name="IDS_ASH_VOICE_INTERACTION_SECONDARY_USER_TOAST_MESSAGE" desc="Message content on the toast that appears when the voice interaction shortcut is pressed but the active user profile is not the primary user profile.">
         Assistant is only available for primary profile.
       </message>
 
@@ -1066,6 +1066,9 @@
       <message name="IDS_DEPRECATED_TOGGLE_HIGH_CONTRAST_MSG" desc="Notification message to tell users about the deprecation of Search+Shift+H shortcut to toggle the high contrast display mode.">
         The shortcut to toggle High Contrast Mode has changed. Please use <ph name="NEW_SHORTCUT">$1<ex>Ctrl+Search+H</ex></ph> instead of <ph name="OLD_SHORTCUT">$2<ex>Search+Shift+H</ex></ph>.
       </message>
+      <message name="IDS_DEPRECATED_SHORTCUT_TITLE" desc="Notification title to tell users that the keyboard accelerator is deprecated.">
+        Shortcut change
+      </message>
 
       <!-- Notification that an accelerator was pressed, so the user knows how to toggle it back -->
       <message name="IDS_HIGH_CONTRAST_ACCEL_TITLE"
diff --git a/ash/ime/ime_controller.cc b/ash/ime/ime_controller.cc
index 85527abc..f6ef013 100644
--- a/ash/ime/ime_controller.cc
+++ b/ash/ime/ime_controller.cc
@@ -15,6 +15,14 @@
 
 ImeController::~ImeController() = default;
 
+void ImeController::AddObserver(Observer* observer) {
+  observers_.AddObserver(observer);
+}
+
+void ImeController::RemoveObserver(Observer* observer) {
+  observers_.RemoveObserver(observer);
+}
+
 void ImeController::BindRequest(mojom::ImeControllerRequest request) {
   bindings_.AddBinding(this, std::move(request));
 }
@@ -121,10 +129,26 @@
   Shell::Get()->system_tray_notifier()->NotifyRefreshIMEMenu(show);
 }
 
+void ImeController::SetCapsLockState(bool caps_enabled) {
+  is_caps_lock_enabled_ = caps_enabled;
+
+  for (ImeController::Observer& observer : observers_)
+    observer.OnCapsLockChanged(caps_enabled);
+}
+
+void ImeController::SetCapsLockFromTray(bool caps_enabled) {
+  if (client_)
+    client_->SetCapsLockFromTray(caps_enabled);
+}
+
 void ImeController::FlushMojoForTesting() {
   client_.FlushForTesting();
 }
 
+bool ImeController::IsCapsLockEnabled() const {
+  return is_caps_lock_enabled_;
+}
+
 std::vector<std::string> ImeController::GetCandidateImesForAccelerator(
     const ui::Accelerator& accelerator) const {
   std::vector<std::string> candidate_ids;
diff --git a/ash/ime/ime_controller.h b/ash/ime/ime_controller.h
index 595815a..92415cb 100644
--- a/ash/ime/ime_controller.h
+++ b/ash/ime/ime_controller.h
@@ -11,6 +11,7 @@
 #include "ash/public/interfaces/ime_controller.mojom.h"
 #include "ash/public/interfaces/ime_info.mojom.h"
 #include "base/macros.h"
+#include "base/observer_list.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 
 namespace ui {
@@ -23,9 +24,18 @@
 // which might live in Chrome browser or in a separate mojo service.
 class ASH_EXPORT ImeController : public mojom::ImeController {
  public:
+  class Observer {
+   public:
+    // Called when the caps lock state has changed.
+    virtual void OnCapsLockChanged(bool enabled) = 0;
+  };
+
   ImeController();
   ~ImeController() override;
 
+  void AddObserver(Observer* observer);
+  void RemoveObserver(Observer* observer);
+
   const mojom::ImeInfo& current_ime() const { return current_ime_; }
 
   const std::vector<mojom::ImeInfo>& available_imes() const {
@@ -49,6 +59,7 @@
   void SwitchToPreviousIme();
   void SwitchImeById(const std::string& ime_id, bool show_message);
   void ActivateImeMenuItem(const std::string& key);
+  void SetCapsLockFromTray(bool caps_enabled);
 
   // Returns true if the switch is allowed and the keystroke should be
   // consumed.
@@ -63,6 +74,10 @@
                   std::vector<mojom::ImeMenuItemPtr> menu_items) override;
   void SetImesManagedByPolicy(bool managed) override;
   void ShowImeMenuOnShelf(bool show) override;
+  void SetCapsLockState(bool caps_enabled) override;
+
+  // Synchronously returns the cached caps lock state.
+  bool IsCapsLockEnabled() const;
 
   void FlushMojoForTesting();
 
@@ -92,6 +107,13 @@
   // Additional menu items for properties of the currently selected IME.
   std::vector<mojom::ImeMenuItem> current_ime_menu_items_;
 
+  // A slightly delayed state value that is updated by asynchronously reported
+  // changes from the ImeControllerClient client (source of truth) which is in
+  // another process. This is required for synchronous method calls in ash.
+  bool is_caps_lock_enabled_ = false;
+
+  base::ObserverList<Observer> observers_;
+
   DISALLOW_COPY_AND_ASSIGN(ImeController);
 };
 
diff --git a/ash/ime/ime_controller_unittest.cc b/ash/ime/ime_controller_unittest.cc
index d1db7faf..687dc216 100644
--- a/ash/ime/ime_controller_unittest.cc
+++ b/ash/ime/ime_controller_unittest.cc
@@ -80,10 +80,12 @@
     last_show_message_ = show_message;
   }
   void ActivateImeMenuItem(const std::string& key) override {}
+  void SetCapsLockFromTray(bool enabled) override { ++set_caps_lock_count_; }
 
   int next_ime_count_ = 0;
   int previous_ime_count_ = 0;
   int switch_ime_count_ = 0;
+  int set_caps_lock_count_ = 0;
   std::string last_switch_ime_id_;
   bool last_show_message_ = false;
 
@@ -265,5 +267,36 @@
   EXPECT_EQ(nacl_mozc_jp, client.last_switch_ime_id_);
 }
 
+TEST_F(ImeControllerTest, SetCapsLock) {
+  ImeController* controller = Shell::Get()->ime_controller();
+  TestImeControllerClient client;
+  EXPECT_EQ(0, client.set_caps_lock_count_);
+
+  controller->SetCapsLockFromTray(true);
+  EXPECT_EQ(0, client.set_caps_lock_count_);
+
+  controller->SetClient(client.CreateInterfacePtr());
+
+  controller->SetCapsLockFromTray(true);
+  controller->FlushMojoForTesting();
+  EXPECT_EQ(1, client.set_caps_lock_count_);
+  // Does not no-op when the state is the same. Should send all notifications.
+  controller->SetCapsLockFromTray(true);
+  controller->FlushMojoForTesting();
+  EXPECT_EQ(2, client.set_caps_lock_count_);
+  controller->SetCapsLockFromTray(false);
+  controller->FlushMojoForTesting();
+  EXPECT_EQ(3, client.set_caps_lock_count_);
+  controller->SetCapsLockFromTray(false);
+  controller->FlushMojoForTesting();
+  EXPECT_EQ(4, client.set_caps_lock_count_);
+
+  EXPECT_FALSE(controller->IsCapsLockEnabled());
+  controller->SetCapsLockState(true);
+  EXPECT_TRUE(controller->IsCapsLockEnabled());
+  controller->SetCapsLockState(false);
+  EXPECT_FALSE(controller->IsCapsLockEnabled());
+}
+
 }  // namespace
 }  // namespace ash
diff --git a/ash/metrics/user_metrics_action.h b/ash/metrics/user_metrics_action.h
index aab3787a..b06188d 100644
--- a/ash/metrics/user_metrics_action.h
+++ b/ash/metrics/user_metrics_action.h
@@ -12,8 +12,6 @@
 // instead of adding things here.
 enum UserMetricsAction {
   UMA_DESKTOP_SWITCH_TASK,
-  UMA_DRAG_MAXIMIZE_LEFT,
-  UMA_DRAG_MAXIMIZE_RIGHT,
   UMA_LAUNCHER_BUTTON_PRESSED_WITH_MOUSE,
   UMA_LAUNCHER_BUTTON_PRESSED_WITH_TOUCH,
   UMA_LAUNCHER_CLICK_ON_APP,
@@ -21,12 +19,6 @@
   UMA_LAUNCHER_LAUNCH_TASK,
   UMA_LAUNCHER_MINIMIZE_TASK,
   UMA_LAUNCHER_SWITCH_TASK,
-  UMA_MAXIMIZE_MODE_DISABLED,
-  UMA_MAXIMIZE_MODE_ENABLED,
-  UMA_MAXIMIZE_MODE_INITIALLY_DISABLED,
-  UMA_MOUSE_DOWN,
-  UMA_PANEL_MINIMIZE_CAPTION_CLICK,
-  UMA_PANEL_MINIMIZE_CAPTION_GESTURE,
   UMA_SHELF_ALIGNMENT_SET_BOTTOM,
   UMA_SHELF_ALIGNMENT_SET_LEFT,
   UMA_SHELF_ALIGNMENT_SET_RIGHT,
@@ -82,11 +74,6 @@
   UMA_STATUS_AREA_VPN_ADD_THIRD_PARTY_CLICKED,
   UMA_STATUS_AREA_VPN_DISCONNECT_CLICKED,
   UMA_STATUS_AREA_VPN_SETTINGS_OPENED,
-  UMA_TOGGLE_MAXIMIZE_CAPTION_CLICK,
-  UMA_TOGGLE_MAXIMIZE_CAPTION_GESTURE,
-  UMA_TOGGLE_SINGLE_AXIS_MAXIMIZE_BORDER_CLICK,
-  UMA_TOUCHPAD_GESTURE_OVERVIEW,
-  UMA_TOUCHSCREEN_TAP_DOWN,
   UMA_TRAY_HELP,
   UMA_TRAY_LOCK_SCREEN,
   UMA_TRAY_NIGHT_LIGHT,
@@ -97,7 +84,6 @@
   UMA_TRAY_SWIPE_TO_CLOSE_UNSUCCESSFUL,
   UMA_TRAY_SWIPE_TO_OPEN_SUCCESSFUL,
   UMA_TRAY_SWIPE_TO_OPEN_UNSUCCESSFUL,
-  UMA_WINDOW_APP_CLOSE_BUTTON_CLICK,
 
   // DEPRECATED: Do not add new values. See top of file.
 };
diff --git a/ash/metrics/user_metrics_recorder.cc b/ash/metrics/user_metrics_recorder.cc
index 8556cac..808d9d8 100644
--- a/ash/metrics/user_metrics_recorder.cc
+++ b/ash/metrics/user_metrics_recorder.cc
@@ -189,12 +189,6 @@
       RecordAction(UserMetricsAction("Desktop_SwitchTask"));
       task_switch_metrics_recorder_.OnTaskSwitch(TaskSwitchSource::DESKTOP);
       break;
-    case UMA_DRAG_MAXIMIZE_LEFT:
-      RecordAction(UserMetricsAction("WindowDrag_MaximizeLeft"));
-      break;
-    case UMA_DRAG_MAXIMIZE_RIGHT:
-      RecordAction(UserMetricsAction("WindowDrag_MaximizeRight"));
-      break;
     case UMA_LAUNCHER_BUTTON_PRESSED_WITH_MOUSE:
       RecordAction(UserMetricsAction("Launcher_ButtonPressed_Mouse"));
       break;
@@ -218,24 +212,6 @@
       RecordAction(UserMetricsAction("Launcher_SwitchTask"));
       task_switch_metrics_recorder_.OnTaskSwitch(TaskSwitchSource::SHELF);
       break;
-    case UMA_MAXIMIZE_MODE_DISABLED:
-      RecordAction(UserMetricsAction("Touchview_Disabled"));
-      break;
-    case UMA_MAXIMIZE_MODE_ENABLED:
-      RecordAction(UserMetricsAction("Touchview_Enabled"));
-      break;
-    case UMA_MAXIMIZE_MODE_INITIALLY_DISABLED:
-      RecordAction(UserMetricsAction("Touchview_Initially_Disabled"));
-      break;
-    case UMA_MOUSE_DOWN:
-      RecordAction(UserMetricsAction("Mouse_Down"));
-      break;
-    case UMA_PANEL_MINIMIZE_CAPTION_CLICK:
-      RecordAction(UserMetricsAction("Panel_Minimize_Caption_Click"));
-      break;
-    case UMA_PANEL_MINIMIZE_CAPTION_GESTURE:
-      RecordAction(UserMetricsAction("Panel_Minimize_Caption_Gesture"));
-      break;
     case UMA_SHELF_ALIGNMENT_SET_BOTTOM:
       RecordAction(UserMetricsAction("Shelf_AlignmentSetBottom"));
       break;
@@ -405,22 +381,6 @@
     case UMA_STATUS_AREA_VPN_SETTINGS_OPENED:
       RecordAction(UserMetricsAction("StatusArea_VPN_Settings"));
       break;
-    case UMA_TOGGLE_MAXIMIZE_CAPTION_CLICK:
-      RecordAction(UserMetricsAction("Caption_ClickTogglesMaximize"));
-      break;
-    case UMA_TOGGLE_MAXIMIZE_CAPTION_GESTURE:
-      RecordAction(UserMetricsAction("Caption_GestureTogglesMaximize"));
-      break;
-    case UMA_TOGGLE_SINGLE_AXIS_MAXIMIZE_BORDER_CLICK:
-      RecordAction(
-          UserMetricsAction("WindowBorder_ClickTogglesSingleAxisMaximize"));
-      break;
-    case UMA_TOUCHPAD_GESTURE_OVERVIEW:
-      RecordAction(UserMetricsAction("Touchpad_Gesture_Overview"));
-      break;
-    case UMA_TOUCHSCREEN_TAP_DOWN:
-      RecordAction(UserMetricsAction("Touchscreen_Down"));
-      break;
     case UMA_TRAY_HELP:
       RecordAction(UserMetricsAction("Tray_Help"));
       break;
@@ -451,9 +411,6 @@
     case UMA_TRAY_SWIPE_TO_OPEN_UNSUCCESSFUL:
       RecordAction(UserMetricsAction("Tray_SwipeToOpen_Unsuccessful"));
       break;
-    case UMA_WINDOW_APP_CLOSE_BUTTON_CLICK:
-      RecordAction(UserMetricsAction("AppCloseButton_Clk"));
-      break;
   }
 }
 
diff --git a/ash/public/interfaces/ime_controller.mojom b/ash/public/interfaces/ime_controller.mojom
index 8bccdf5f..0b2768e 100644
--- a/ash/public/interfaces/ime_controller.mojom
+++ b/ash/public/interfaces/ime_controller.mojom
@@ -26,6 +26,10 @@
   // some Chinese IMEs) prefer this to keeping the IME menu under the primary
   // system tray menu.
   ShowImeMenuOnShelf(bool show);
+
+  // Report caps lock state changes from chrome (which is the source of truth)
+  // to the tray.
+  SetCapsLockState(bool enabled);
 };
 
 // Interface for ash to send input method requests to its client (e.g. Chrome).
@@ -48,4 +52,12 @@
   // Activates an input method menu item. The |key| must be a value from the
   // ImeMenuItems provided via RefreshIme. Does nothing if the |key| is invalid.
   ActivateImeMenuItem(string key);
+
+  // When the caps lock state change originates from the tray (i.e. clicking the
+  // caps lock toggle from the settings menu from the caps lock icon), propagate
+  // the change to the client without sending a change notification back to the
+  // tray.
+  // TODO(crbug/759435): Ideally this interaction should only be to disable the
+  // caps lock.
+  SetCapsLockFromTray(bool enabled);
 };
diff --git a/ash/resources/vector_icons/BUILD.gn b/ash/resources/vector_icons/BUILD.gn
index 536c9ac1..af5f1c5ca 100644
--- a/ash/resources/vector_icons/BUILD.gn
+++ b/ash/resources/vector_icons/BUILD.gn
@@ -77,6 +77,7 @@
     "notification_feedback_button.1x.icon",
     "notification_feedback_button.icon",
     "notification_low_power_battery.icon",
+    "notification_settings.icon",
     "notification_timer.icon",
     "palette_action_capture_region.1x.icon",
     "palette_action_capture_region.icon",
diff --git a/ash/resources/vector_icons/notification_settings.icon b/ash/resources/vector_icons/notification_settings.icon
new file mode 100644
index 0000000..9b861f29
--- /dev/null
+++ b/ash/resources/vector_icons/notification_settings.icon
@@ -0,0 +1,52 @@
+// 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, 19.63f, 12.98f,
+R_CUBIC_TO, 0.04f, -0.32f, 0.07f, -0.64f, 0.07f, -0.97f,
+R_CUBIC_TO, 0, -0.33f, -0.03f, -0.65f, -0.07f, -0.97f,
+R_LINE_TO, 2.17f, -1.65f,
+R_CUBIC_TO, 0.2f, -0.15f, 0.25f, -0.42f, 0.12f, -0.64f,
+R_LINE_TO, -2.06f, -3.46f,
+R_CUBIC_TO, -0.13f, -0.21f, -0.39f, -0.3f, -0.63f, -0.21f,
+R_LINE_TO, -2.56f, 1,
+R_CUBIC_TO, -0.53f, -0.39f, -1.11f, -0.73f, -1.74f, -0.98f,
+R_LINE_TO, -0.38f, -2.65f,
+R_CUBIC_TO, -0.05f, -0.23f, -0.26f, -0.42f, -0.51f, -0.42f,
+R_H_LINE_TO, -4.11f,
+R_CUBIC_TO, -0.26f, 0, -0.47f, 0.19f, -0.51f, 0.42f,
+R_LINE_TO, -0.38f, 2.65f,
+R_CUBIC_TO, -0.63f, 0.26f, -1.21f, 0.59f, -1.74f, 0.99f,
+LINE_TO, 4.75f, 5.05f,
+R_CUBIC_TO, -0.23f, -0.08f, -0.5f, 0, -0.63f, 0.22f,
+LINE_TO, 2.07f, 8.73f,
+R_CUBIC_TO, -0.13f, 0.22f, -0.07f, 0.49f, 0.12f, 0.64f,
+R_LINE_TO, 2.17f, 1.66f,
+R_CUBIC_TO, -0.04f, 0.32f, -0.07f, 0.65f, -0.07f, 0.98f,
+R_CUBIC_TO, 0, 0.33f, 0.03f, 0.66f, 0.07f, 0.98f,
+LINE_TO, 2.19f, 14.63f,
+R_CUBIC_TO, -0.19f, 0.15f, -0.25f, 0.42f, -0.12f, 0.64f,
+R_LINE_TO, 2.06f, 3.47f,
+R_CUBIC_TO, 0.13f, 0.22f, 0.4f, 0.31f, 0.63f, 0.22f,
+R_LINE_TO, 2.56f, -1,
+R_CUBIC_TO, 0.53f, 0.4f, 1.11f, 0.73f, 1.74f, 0.99f,
+R_LINE_TO, 0.39f, 2.65f,
+R_CUBIC_TO, 0.04f, 0.24f, 0.25f, 0.42f, 0.51f, 0.42f,
+R_H_LINE_TO, 4.11f,
+R_CUBIC_TO, 0.26f, 0, 0.47f, -0.18f, 0.51f, -0.42f,
+R_LINE_TO, 0.38f, -2.65f,
+R_CUBIC_TO, 0.63f, -0.25f, 1.21f, -0.58f, 1.74f, -0.98f,
+R_LINE_TO, 2.56f, 1,
+R_CUBIC_TO, 0.23f, 0.09f, 0.5f, 0, 0.63f, -0.21f,
+R_LINE_TO, 2.06f, -3.46f,
+R_CUBIC_TO, 0.13f, -0.21f, 0.07f, -0.48f, -0.12f, -0.64f,
+R_LINE_TO, -2.17f, -1.65f,
+CLOSE,
+MOVE_TO, 12, 15,
+R_CUBIC_TO, -1.66f, 0, -3, -1.34f, -3, -3,
+R_CUBIC_TO, 0, -1.66f, 1.34f, -3, 3, -3,
+R_CUBIC_TO, 1.66f, 0, 3, 1.34f, 3, 3,
+R_CUBIC_TO, 0, 1.66f, -1.34f, 3, -3, 3,
+CLOSE,
+END
diff --git a/ash/shelf/app_list_button.cc b/ash/shelf/app_list_button.cc
index df11f8a..10277465 100644
--- a/ash/shelf/app_list_button.cc
+++ b/ash/shelf/app_list_button.cc
@@ -154,14 +154,14 @@
       return;
     case ui::ET_GESTURE_TAP:
     case ui::ET_GESTURE_TAP_CANCEL:
-      if (IsVoiceInteractionActive()) {
+      if (UseVoiceInteractionStyle()) {
         voice_interaction_overlay_->EndAnimation();
         voice_interaction_animation_delay_timer_->Stop();
       }
       ImageButton::OnGestureEvent(event);
       return;
     case ui::ET_GESTURE_TAP_DOWN:
-      if (IsVoiceInteractionActive()) {
+      if (UseVoiceInteractionStyle()) {
         voice_interaction_animation_delay_timer_->Start(
             FROM_HERE,
             base::TimeDelta::FromMilliseconds(
@@ -174,7 +174,7 @@
       ImageButton::OnGestureEvent(event);
       return;
     case ui::ET_GESTURE_LONG_PRESS:
-      if (IsVoiceInteractionActive()) {
+      if (UseVoiceInteractionStyle()) {
         base::RecordAction(base::UserMetricsAction(
             "VoiceInteraction.Started.AppListButtonLongPress"));
         Shell::Get()->app_list()->StartVoiceInteractionSession();
@@ -185,7 +185,7 @@
       }
       return;
     case ui::ET_GESTURE_LONG_TAP:
-      if (IsVoiceInteractionActive()) {
+      if (UseVoiceInteractionStyle()) {
         // Also consume the long tap event. This happens after the user long
         // presses and lifts the finger. We already handled the long press
         // ignore the long tap to avoid bringing up the context menu again.
@@ -370,7 +370,7 @@
   // factors.
   float ring_outer_radius_dp = 7.f;
   float ring_thickness_dp = 1.5f;
-  if (IsVoiceInteractionActive()) {
+  if (UseVoiceInteractionStyle()) {
     ring_outer_radius_dp = 8.f;
     ring_thickness_dp = 1.f;
   }
@@ -383,7 +383,7 @@
     fg_flags.setStyle(cc::PaintFlags::kStroke_Style);
     fg_flags.setColor(kShelfIconColor);
 
-    if (IsVoiceInteractionActive())
+    if (UseVoiceInteractionStyle())
       // active: 100% alpha, inactive: 54% alpha
       fg_flags.setAlpha(voice_interaction_state_ ==
                                 ash::VoiceInteractionState::RUNNING
@@ -396,7 +396,7 @@
     // Make sure the center of the circle lands on pixel centers.
     canvas->DrawCircle(circle_center, radius, fg_flags);
 
-    if (IsVoiceInteractionActive()) {
+    if (UseVoiceInteractionStyle()) {
       fg_flags.setAlpha(255);
       const float kCircleRadiusDp = 5.f;
       fg_flags.setStyle(cc::PaintFlags::kFill_Style);
@@ -416,7 +416,8 @@
   // back button arrow in addition to the app list button circle.
   const int x_mid = width() / 2.f;
   const int y_mid = height() / 2.f;
-  const bool is_tablet_mode = Shell::Get()
+  const bool is_tablet_mode = Shell::Get()->tablet_mode_controller() &&
+                              Shell::Get()
                                   ->tablet_mode_controller()
                                   ->IsTabletModeWindowManagerEnabled();
   const bool is_animating = shelf_view_->is_tablet_mode_animation_running();
@@ -458,6 +459,21 @@
                     kShelfButtonSize / 2.f);
 }
 
+void AppListButton::OnBoundsAnimationStarted() {
+  // TODO(crbug.com/758402): Update ink drop bounds with app list button bounds.
+  // Hides the app list button ink drop during a bounds animation.
+  if (is_showing_app_list_)
+    AnimateInkDrop(views::InkDropState::DEACTIVATED, nullptr);
+}
+
+void AppListButton::OnBoundsAnimationFinished() {
+  // TODO(crbug.com/758402): Update ink drop bounds with app list button bounds.
+  // Reactivate the app list button ink drop after a bounds animation is
+  // finished.
+  if (is_showing_app_list_)
+    AnimateInkDrop(views::InkDropState::ACTIVATED, nullptr);
+}
+
 void AppListButton::OnAppListVisibilityChanged(bool shown,
                                                aura::Window* root_window) {
   aura::Window* window = GetWidget() ? GetWidget()->GetNativeWindow() : nullptr;
@@ -509,6 +525,11 @@
   SchedulePaint();
 }
 
+void AppListButton::OnVoiceInteractionSetupCompleted() {
+  voice_interaction_setup_completed_ = true;
+  SchedulePaint();
+}
+
 void AppListButton::OnActiveUserSessionChanged(const AccountId& account_id) {
   SchedulePaint();
 
@@ -539,12 +560,13 @@
 
 void AppListButton::StartVoiceInteractionAnimation() {
   // We only show the voice interaction icon and related animation when the
-  // shelf is at the bottom position and voice interaction is not running.
+  // shelf is at the bottom position and voice interaction is not running and
+  // voice interaction setup flow has completed.
   ShelfAlignment alignment = shelf_->alignment();
-  bool show_icon =
-      (alignment == SHELF_ALIGNMENT_BOTTOM ||
-       alignment == SHELF_ALIGNMENT_BOTTOM_LOCKED) &&
-      (voice_interaction_state_ == ash::VoiceInteractionState::STOPPED);
+  bool show_icon = (alignment == SHELF_ALIGNMENT_BOTTOM ||
+                    alignment == SHELF_ALIGNMENT_BOTTOM_LOCKED) &&
+                   voice_interaction_state_ == VoiceInteractionState::STOPPED &&
+                   voice_interaction_setup_completed_;
   voice_interaction_overlay_->StartAnimation(show_icon);
 }
 
@@ -585,10 +607,12 @@
   }
 }
 
-bool AppListButton::IsVoiceInteractionActive() {
+bool AppListButton::UseVoiceInteractionStyle() {
   if (voice_interaction_overlay_ &&
       chromeos::switches::IsVoiceInteractionEnabled() &&
-      is_primary_user_active_ && voice_interaction_settings_enabled_) {
+      is_primary_user_active_ &&
+      (voice_interaction_settings_enabled_ ||
+       !voice_interaction_setup_completed_)) {
     return true;
   }
   return false;
diff --git a/ash/shelf/app_list_button.h b/ash/shelf/app_list_button.h
index 769d4621..a8c2e5c 100644
--- a/ash/shelf/app_list_button.h
+++ b/ash/shelf/app_list_button.h
@@ -54,6 +54,11 @@
   // gfx::Point if the back arrow is not shown.
   gfx::Point GetBackButtonCenterPoint() const;
 
+  // Called by ShelfView to notify the app list button that it has started or
+  // finished a bounds animation.
+  void OnBoundsAnimationStarted();
+  void OnBoundsAnimationFinished();
+
  protected:
   // views::ImageButton:
   bool OnMousePressed(const ui::MouseEvent& event) override;
@@ -75,6 +80,7 @@
   void OnVoiceInteractionStatusChanged(
       ash::VoiceInteractionState state) override;
   void OnVoiceInteractionEnabled(bool enabled) override;
+  void OnVoiceInteractionSetupCompleted() override;
 
   // SessionObserver:
   void OnActiveUserSessionChanged(const AccountId& account_id) override;
@@ -90,8 +96,8 @@
   // portion is clicked or tapped.
   void GenerateAndSendBackEvent(const ui::LocatedEvent& original_event);
 
-  // Whether voice interaction is currently active.
-  bool IsVoiceInteractionActive();
+  // Whether the voice interaction style should be used.
+  bool UseVoiceInteractionStyle();
 
   // True if the app list is currently showing for this display.
   // This is useful because other IsApplistVisible functions aren't per-display.
@@ -122,7 +128,10 @@
   bool is_primary_user_active_ = false;
 
   // Whether voice interaction is enabled in system settings.
-  bool voice_interaction_settings_enabled_ = true;
+  bool voice_interaction_settings_enabled_ = false;
+
+  // Whether voice intearction setup flow has completed.
+  bool voice_interaction_setup_completed_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(AppListButton);
 };
diff --git a/ash/shelf/app_list_button_unittest.cc b/ash/shelf/app_list_button_unittest.cc
index 47e2419..549bbde 100644
--- a/ash/shelf/app_list_button_unittest.cc
+++ b/ash/shelf/app_list_button_unittest.cc
@@ -64,6 +64,9 @@
   // Simulate two user with primary user as active.
   CreateUserSessions(2);
 
+  // Enable voice interaction in system settings.
+  Shell::Get()->NotifyVoiceInteractionEnabled(true);
+
   ui::GestureEvent long_press =
       CreateGestureEvent(ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
   SendGestureEvent(&long_press);
@@ -91,6 +94,9 @@
   // Simulate two user with primary user as active.
   CreateUserSessions(2);
 
+  // Enable voice interaction in system settings.
+  Shell::Get()->NotifyVoiceInteractionEnabled(true);
+
   ui::GestureEvent long_press =
       CreateGestureEvent(ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
   SendGestureEvent(&long_press);
@@ -106,6 +112,9 @@
   SimulateUserLogin("user1@test.com");
   SimulateUserLogin("user2@test.com");
 
+  // Enable voice interaction in system settings.
+  Shell::Get()->NotifyVoiceInteractionEnabled(true);
+
   ui::GestureEvent long_press =
       CreateGestureEvent(ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
   SendGestureEvent(&long_press);
@@ -127,15 +136,42 @@
   // Simulate two user with primary user as active.
   CreateUserSessions(2);
 
-  // Notify voice interaction settings disabled.
+  // Simulate a user who has already completed setup flow, but disabled voice
+  // interaction in settings.
+  Shell::Get()->NotifyVoiceInteractionEnabled(false);
+  Shell::Get()->NotifyVoiceInteractionSetupCompleted();
+
+  ui::GestureEvent long_press =
+      CreateGestureEvent(ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
+  SendGestureEvent(&long_press);
+  RunAllPendingInMessageLoop();
+  // After value prop has been accepted, if voice interaction is disalbed in
+  // settings we should not handle long press action in app list button.
+  EXPECT_EQ(0u, test_app_list_presenter.voice_session_count());
+}
+
+TEST_F(VoiceInteractionAppListButtonTest,
+       LongPressGestureBeforeSetupCompleted) {
+  app_list::test::TestAppListPresenter test_app_list_presenter;
+  Shell::Get()->app_list()->SetAppListPresenter(
+      test_app_list_presenter.CreateInterfacePtrAndBind());
+
+  EXPECT_TRUE(base::CommandLine::ForCurrentProcess()->HasSwitch(
+      chromeos::switches::kEnableVoiceInteraction));
+
+  // Simulate two user with primary user as active.
+  CreateUserSessions(2);
+
+  // Disable voice interaction in system settings.
   Shell::Get()->NotifyVoiceInteractionEnabled(false);
 
   ui::GestureEvent long_press =
       CreateGestureEvent(ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
   SendGestureEvent(&long_press);
   RunAllPendingInMessageLoop();
-  // Voice interaction is disabled in settings, so the count here should be 0.
-  EXPECT_EQ(0u, test_app_list_presenter.voice_session_count());
+  // Before setup flow completed we should show the animation even if the
+  // settings are disabled.
+  EXPECT_EQ(1u, test_app_list_presenter.voice_session_count());
 }
 
 namespace {
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc
index c496cb39..0fea3eb 100644
--- a/ash/shelf/shelf_layout_manager.cc
+++ b/ash/shelf/shelf_layout_manager.cc
@@ -32,6 +32,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "ui/app_list/app_list_constants.h"
 #include "ui/app_list/app_list_features.h"
+#include "ui/app_list/presenter/app_list.h"
 #include "ui/app_list/views/app_list_view.h"
 #include "ui/base/ui_base_switches.h"
 #include "ui/compositor/layer.h"
@@ -75,11 +76,6 @@
 // the auto hidden shelf when the shelf is on the boundary between displays.
 constexpr int kMaxAutoHideShowShelfRegionSize = 10;
 
-// TODO(minch): Add unit tests for this value. http://crbug.com/755185.
-// The velocity the app list must be dragged in order to change the state of the
-// app list for fling event, measured in DIPs/event.
-constexpr int kAppListDragVelocityThreshold = 100;
-
 ui::Layer* GetLayer(views::Widget* widget) {
   return widget->GetNativeView()->layer();
 }
@@ -1118,10 +1114,9 @@
           gesture_in_screen.details().scroll_y_hint())) {
     gesture_drag_status_ = GESTURE_DRAG_APPLIST_IN_PROGRESS;
     Shell::Get()->ShowAppList(app_list::kSwipeFromShelf);
-    Shell::Get()->UpdateAppListYPositionAndOpacity(
+    Shell::Get()->app_list()->UpdateYPositionAndOpacity(
         gesture_in_screen.location().y(),
-        GetAppListBackgroundOpacityOnShelfOpacity(),
-        false /* is_end_gesture */);
+        GetAppListBackgroundOpacityOnShelfOpacity());
   } else {
     // Disable the shelf dragging if the fullscreen app list is opened.
     if (app_list::features::IsFullscreenAppListEnabled() &&
@@ -1140,20 +1135,17 @@
 void ShelfLayoutManager::UpdateGestureDrag(
     const ui::GestureEvent& gesture_in_screen) {
   if (gesture_drag_status_ == GESTURE_DRAG_APPLIST_IN_PROGRESS) {
-    // Dismiss the app list if the shelf changed to vertical alignment or mode
-    // changed to non-tablet mode during dragging.
-    if (!Shell::Get()
-             ->tablet_mode_controller()
-             ->IsTabletModeWindowManagerEnabled() ||
-        !shelf_->IsHorizontalAlignment()) {
+    // Dismiss the app list if the shelf changed to vertical alignment during
+    // dragging.
+    if (!shelf_->IsHorizontalAlignment()) {
       Shell::Get()->DismissAppList();
+      gesture_drag_amount_ = 0.f;
       gesture_drag_status_ = GESTURE_DRAG_NONE;
       return;
     }
-    Shell::Get()->UpdateAppListYPositionAndOpacity(
+    Shell::Get()->app_list()->UpdateYPositionAndOpacity(
         gesture_in_screen.location().y(),
-        GetAppListBackgroundOpacityOnShelfOpacity(),
-        false /* is_end_gesture */);
+        GetAppListBackgroundOpacityOnShelfOpacity());
     gesture_drag_amount_ += gesture_in_screen.details().scroll_y();
   } else {
     gesture_drag_amount_ +=
@@ -1218,34 +1210,46 @@
 
 void ShelfLayoutManager::CompleteAppListDrag(
     const ui::GestureEvent& gesture_in_screen) {
-  bool should_show_app_list = false;
+  // Change the shelf alignment to vertical during drag will reset
+  // |gesture_drag_status_| to |GESTURE_DRAG_NONE|.
+  if (gesture_drag_status_ == GESTURE_DRAG_NONE)
+    return;
+
+  using app_list::mojom::AppListState;
+  AppListState app_list_state = AppListState::PEEKING;
   if (gesture_in_screen.type() == ui::ET_SCROLL_FLING_START &&
       fabs(gesture_in_screen.details().velocity_y()) >
           kAppListDragVelocityThreshold) {
-    // If the scroll sequence terminates with a fling, show the app list if
-    // the fling was fast enough and in the correct direction, otherwise close
-    // it.
-    should_show_app_list = gesture_in_screen.details().velocity_y() < 0;
+    // If the scroll sequence terminates with a fling, show the fullscreen app
+    // list if the fling was fast enough and in the correct direction, otherwise
+    // close it.
+    app_list_state = gesture_in_screen.details().velocity_y() < 0
+                         ? AppListState::FULLSCREEN_ALL_APPS
+                         : AppListState::CLOSED;
   } else {
-    // Show the app list if the drag amount exceeds a constant threshold.
-    should_show_app_list =
-        -gesture_drag_amount_ > kAppListDragDistanceThreshold;
+    // Snap the app list to corresponding state according to the snapping
+    // thresholds.
+    if (Shell::Get()
+            ->tablet_mode_controller()
+            ->IsTabletModeWindowManagerEnabled()) {
+      app_list_state =
+          -gesture_drag_amount_ > kAppListDragSnapToFullscreenThreshold
+              ? AppListState::FULLSCREEN_ALL_APPS
+              : AppListState::CLOSED;
+    } else {
+      if (-gesture_drag_amount_ <= kAppListDragSnapToClosedThreshold)
+        app_list_state = AppListState::CLOSED;
+      else if (-gesture_drag_amount_ <= kAppListDragSnapToPeekingThreshold)
+        app_list_state = AppListState::PEEKING;
+      else
+        app_list_state = AppListState::FULLSCREEN_ALL_APPS;
+    }
   }
 
-  if (should_show_app_list) {
-    Shell::Get()->UpdateAppListYPositionAndOpacity(
-        display::Screen::GetScreen()
-            ->GetDisplayNearestWindow(shelf_widget_->GetNativeWindow())
-            .work_area()
-            .y(),
-        GetAppListBackgroundOpacityOnShelfOpacity(), true /* is_end_gesture */);
-    UMA_HISTOGRAM_ENUMERATION(app_list::kAppListToggleMethodHistogram,
-                              app_list::kSwipeFromShelf,
-                              app_list::kMaxAppListToggleMethod);
-
-  } else {
-    Shell::Get()->DismissAppList();
-  }
+  Shell::Get()->app_list()->EndDragFromShelf(app_list_state);
+  UMA_HISTOGRAM_ENUMERATION(app_list::kAppListToggleMethodHistogram,
+                            app_list::kSwipeFromShelf,
+                            app_list::kMaxAppListToggleMethod);
 
   gesture_drag_status_ = GESTURE_DRAG_NONE;
 }
@@ -1266,14 +1270,9 @@
   if (!app_list::features::IsFullscreenAppListEnabled())
     return false;
 
-  // Fullscreen app list can only be dragged from bottom alignment shelf in the
-  // tablet mode.
-  if (!Shell::Get()
-           ->tablet_mode_controller()
-           ->IsTabletModeWindowManagerEnabled() ||
-      !shelf_->IsHorizontalAlignment()) {
+  // Fullscreen app list can only be dragged from bottom alignment shelf.
+  if (!shelf_->IsHorizontalAlignment())
     return false;
-  }
 
   // If the shelf is not visible, swiping up should show the shelf.
   if (!IsVisible())
diff --git a/ash/shelf/shelf_layout_manager.h b/ash/shelf/shelf_layout_manager.h
index 43327c34..18262f8 100644
--- a/ash/shelf/shelf_layout_manager.h
+++ b/ash/shelf/shelf_layout_manager.h
@@ -57,9 +57,18 @@
       public wm::WmSnapToPixelLayoutManager,
       public SessionObserver {
  public:
-  // The snapping threshold for dragging app list from shelf in tablet mode. App
-  // list should snap to fullscreen if the drag amount exceeds this value.
-  static constexpr int kAppListDragDistanceThreshold = 320;
+  // The snapping threshold for dragging app list from shelf in tablet mode,
+  // measured in DIPs.
+  static constexpr int kAppListDragSnapToFullscreenThreshold = 320;
+
+  // The snapping thresholds for dragging app list from shelf in laptop mode,
+  // measured in DIPs.
+  static constexpr int kAppListDragSnapToClosedThreshold = 144;
+  static constexpr int kAppListDragSnapToPeekingThreshold = 561;
+
+  // The velocity the app list must be dragged in order to change the state of
+  // the app list for fling event, measured in DIPs/event.
+  static constexpr int kAppListDragVelocityThreshold = 100;
 
   ShelfLayoutManager(ShelfWidget* shelf_widget, Shelf* shelf);
   ~ShelfLayoutManager() override;
diff --git a/ash/shelf/shelf_layout_manager_unittest.cc b/ash/shelf/shelf_layout_manager_unittest.cc
index a0e1651f..bf765ca 100644
--- a/ash/shelf/shelf_layout_manager_unittest.cc
+++ b/ash/shelf/shelf_layout_manager_unittest.cc
@@ -317,97 +317,58 @@
   DISALLOW_COPY_AND_ASSIGN(ShelfLayoutManagerTest);
 };
 
-TEST_F(ShelfLayoutManagerTest, SwipingUpOnShelfForFullscreenAppList) {
-  // TODO: investigate failure in mash, http://crbug.com/695686.
-  if (Shell::GetAshConfig() == Config::MASH)
-    return;
+class ShelfLayoutManagerFullscreenAppListTest : public ShelfLayoutManagerTest {
+ public:
+  ShelfLayoutManagerFullscreenAppListTest() {}
 
-  // TODO(minch): Add more tests for shelf alignment or mode changed during
-  // dragging. http://crbug.com/747016.
+  void SetUp() override {
+    ShelfLayoutManagerTest::SetUp();
+
+    scoped_feature_list.InitAndEnableFeature(
+        app_list::features::kEnableFullscreenAppList);
+  }
+
+  void StartScroll(gfx::Point start) {
+    timestamp_ = base::TimeTicks::Now();
+    current_point_ = start;
+    ui::GestureEvent event = ui::GestureEvent(
+        current_point_.x(), current_point_.y(), ui::EF_NONE, timestamp_,
+        ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN, 0, -1.0f));
+    GetShelfLayoutManager()->ProcessGestureEvent(event);
+  }
+
+  void UpdateScroll(float delta_y) {
+    IncreaseTimestamp();
+    current_point_.set_y(current_point_.y() + delta_y);
+    ui::GestureEvent event = ui::GestureEvent(
+        current_point_.x(), current_point_.y(), ui::EF_NONE, timestamp_,
+        ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 0, delta_y));
+    GetShelfLayoutManager()->ProcessGestureEvent(event);
+  }
+
+  void EndScroll(bool is_fling, float velocity_y) {
+    IncreaseTimestamp();
+    ui::GestureEventDetails event_details =
+        is_fling
+            ? ui::GestureEventDetails(ui::ET_SCROLL_FLING_START, 0, velocity_y)
+            : ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END);
+    ui::GestureEvent event =
+        ui::GestureEvent(current_point_.x(), current_point_.y(), ui::EF_NONE,
+                         timestamp_, event_details);
+    GetShelfLayoutManager()->ProcessGestureEvent(event);
+  }
+
+  void IncreaseTimestamp() {
+    timestamp_ += base::TimeDelta::FromMilliseconds(25);
+  }
+
+ private:
   base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(
-      app_list::features::kEnableFullscreenAppList);
-  Shell* shell = Shell::Get();
-  shell->tablet_mode_controller()->EnableTabletModeWindowManager(true);
-  Shelf* shelf = GetPrimaryShelf();
-  EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM, shelf->alignment());
-  EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_NEVER, shelf->auto_hide_behavior());
-  EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState());
+  base::TimeTicks timestamp_;
+  gfx::Point current_point_;
 
-  // Note: A window must be visible in order to hide the shelf.
-  views::Widget* widget = CreateTestWidget();
-
-  app_list::test::TestAppListPresenter test_app_list_presenter;
-  shell->app_list()->SetAppListPresenter(
-      test_app_list_presenter.CreateInterfacePtrAndBind());
-
-  ui::test::EventGenerator& generator(GetEventGenerator());
-  constexpr base::TimeDelta kTimeDelta = base::TimeDelta::FromMilliseconds(100);
-  constexpr int kNumScrollSteps = 4;
-
-  gfx::Point start = GetShelfWidget()->GetWindowBoundsInScreen().CenterPoint();
-  gfx::Vector2d delta;
-
-  // Swiping up more than the threshold should show the app list.
-  delta.set_y(ShelfLayoutManager::kAppListDragDistanceThreshold + 10);
-  gfx::Point end = start - delta;
-  generator.GestureScrollSequence(start, end, kTimeDelta, kNumScrollSteps);
-  RunAllPendingInMessageLoop();
-  EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState());
-  EXPECT_EQ(1u, test_app_list_presenter.show_count());
-  EXPECT_EQ(0u, test_app_list_presenter.dismiss_count());
-  EXPECT_GE(test_app_list_presenter.set_y_position_count(), 1u);
-
-  // Swiping up less or equal to the threshold should dismiss the app list.
-  delta.set_y(ShelfLayoutManager::kAppListDragDistanceThreshold - 10);
-  end = start - delta;
-  // TODO(minch): investigate failure without EnableMaximizeMode again here.
-  // http://crbug.com/746481.
-  shell->tablet_mode_controller()->EnableTabletModeWindowManager(true);
-  generator.GestureScrollSequence(start, end, kTimeDelta, kNumScrollSteps);
-  RunAllPendingInMessageLoop();
-  EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState());
-  EXPECT_EQ(2u, test_app_list_presenter.show_count());
-  EXPECT_EQ(1u, test_app_list_presenter.dismiss_count());
-  EXPECT_GE(test_app_list_presenter.set_y_position_count(), 1u);
-
-  // Swiping down on the shelf should hide it.
-  end = start + delta;
-  generator.GestureScrollSequence(start, end, kTimeDelta, kNumScrollSteps);
-  EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState());
-  EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState());
-  EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, shelf->auto_hide_behavior());
-
-  // Swiping up should show the shelf but not the app list if shelf is hidden.
-  generator.GestureScrollSequence(end, start, kTimeDelta, kNumScrollSteps);
-  RunAllPendingInMessageLoop();
-  EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState());
-  EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_NEVER, shelf->auto_hide_behavior());
-  EXPECT_EQ(2u, test_app_list_presenter.show_count());
-  EXPECT_EQ(1u, test_app_list_presenter.dismiss_count());
-  EXPECT_GE(test_app_list_presenter.set_y_position_count(), 1u);
-
-  // Swiping down should hide the shelf.
-  generator.GestureScrollSequence(start, end, kTimeDelta, kNumScrollSteps);
-  EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState());
-  EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState());
-  EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, shelf->auto_hide_behavior());
-
-  // Minimize the visible window, the shelf should be shown if there are no
-  // visible windows, even in auto-hide mode.
-  widget->Minimize();
-  EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState());
-  EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState());
-  EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, shelf->auto_hide_behavior());
-
-  // Swiping up on the shelf in this state should open the app list.
-  delta.set_y(ShelfLayoutManager::kAppListDragDistanceThreshold + 10);
-  end = start - delta;
-  generator.GestureScrollSequence(start, end, kTimeDelta, kNumScrollSteps);
-  RunAllPendingInMessageLoop();
-  EXPECT_EQ(3u, test_app_list_presenter.show_count());
-  EXPECT_EQ(1u, test_app_list_presenter.dismiss_count());
-}
+  DISALLOW_COPY_AND_ASSIGN(ShelfLayoutManagerFullscreenAppListTest);
+};
 
 void ShelfLayoutManagerTest::RunGestureDragTests(gfx::Vector2d delta) {
   Shelf* shelf = GetPrimaryShelf();
@@ -1484,11 +1445,228 @@
   }
 }
 
+// If swiping up on shelf ends with fling event, the app list state should
+// depends on the fling velocity.
+TEST_F(ShelfLayoutManagerFullscreenAppListTest,
+       FlingUpOnShelfForFullscreenAppList) {
+  Shelf* shelf = GetPrimaryShelf();
+  EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM, shelf->alignment());
+  EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_NEVER, shelf->auto_hide_behavior());
+  EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState());
+
+  app_list::test::TestAppListPresenter test_app_list_presenter;
+  Shell::Get()->app_list()->SetAppListPresenter(
+      test_app_list_presenter.CreateInterfacePtrAndBind());
+  gfx::Point start = GetShelfWidget()->GetWindowBoundsInScreen().CenterPoint();
+
+  // Fling up that exceeds the velocity threshold should show the fullscreen app
+  // list.
+  StartScroll(start);
+  UpdateScroll(-ShelfLayoutManager::kAppListDragSnapToPeekingThreshold);
+  EndScroll(true /* is_fling */,
+            -(ShelfLayoutManager::kAppListDragVelocityThreshold + 10));
+  RunAllPendingInMessageLoop();
+  EXPECT_EQ(1u, test_app_list_presenter.show_count());
+  EXPECT_GE(test_app_list_presenter.set_y_position_count(), 1u);
+  EXPECT_EQ(app_list::mojom::AppListState::FULLSCREEN_ALL_APPS,
+            test_app_list_presenter.app_list_state());
+
+  // Fling down that exceeds the velocity threshold should close the app list.
+  StartScroll(start);
+  UpdateScroll(-ShelfLayoutManager::kAppListDragSnapToPeekingThreshold);
+  EndScroll(true /* is_fling */,
+            ShelfLayoutManager::kAppListDragVelocityThreshold + 10);
+  RunAllPendingInMessageLoop();
+  EXPECT_EQ(2u, test_app_list_presenter.show_count());
+  EXPECT_EQ(app_list::mojom::AppListState::CLOSED,
+            test_app_list_presenter.app_list_state());
+
+  // Fling the app list not exceed the velocity threshold, the state depends on
+  // the drag amount.
+  StartScroll(start);
+  UpdateScroll(-(ShelfLayoutManager::kAppListDragSnapToPeekingThreshold - 10));
+  EndScroll(true /* is_fling */,
+            -(ShelfLayoutManager::kAppListDragVelocityThreshold - 10));
+  RunAllPendingInMessageLoop();
+  EXPECT_EQ(3u, test_app_list_presenter.show_count());
+  EXPECT_EQ(app_list::mojom::AppListState::PEEKING,
+            test_app_list_presenter.app_list_state());
+}
+
+// Change the shelf alignment during dragging should dismiss the app list.
+TEST_F(ShelfLayoutManagerFullscreenAppListTest,
+       ChangeShelfAlignmentDuringAppListDragging) {
+  Shelf* shelf = GetPrimaryShelf();
+  EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM, shelf->alignment());
+  EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_NEVER, shelf->auto_hide_behavior());
+  EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState());
+
+  app_list::test::TestAppListPresenter test_app_list_presenter;
+  Shell::Get()->app_list()->SetAppListPresenter(
+      test_app_list_presenter.CreateInterfacePtrAndBind());
+
+  StartScroll(GetShelfWidget()->GetWindowBoundsInScreen().CenterPoint());
+  UpdateScroll(-ShelfLayoutManager::kAppListDragSnapToPeekingThreshold);
+  shelf->SetAlignment(SHELF_ALIGNMENT_LEFT);
+  // Note, value -10 here has no specific meaning, it only used to make the
+  // event scroll up a little bit.
+  UpdateScroll(-10);
+  EndScroll(false /* is_fling */, 0.f);
+  RunAllPendingInMessageLoop();
+  EXPECT_EQ(1u, test_app_list_presenter.show_count());
+  EXPECT_EQ(1u, test_app_list_presenter.dismiss_count());
+  EXPECT_GE(test_app_list_presenter.set_y_position_count(), 1u);
+}
+
+TEST_F(ShelfLayoutManagerFullscreenAppListTest,
+       SwipingUpOnShelfInTabletModeForFullscreenAppList) {
+  // TODO: investigate failure in mash, http://crbug.com/695686.
+  if (Shell::GetAshConfig() == Config::MASH)
+    return;
+
+  Shell* shell = Shell::Get();
+  shell->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shelf* shelf = GetPrimaryShelf();
+  EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM, shelf->alignment());
+  EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_NEVER, shelf->auto_hide_behavior());
+  EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState());
+
+  // Note: A window must be visible in order to hide the shelf.
+  views::Widget* widget = CreateTestWidget();
+
+  app_list::test::TestAppListPresenter test_app_list_presenter;
+  shell->app_list()->SetAppListPresenter(
+      test_app_list_presenter.CreateInterfacePtrAndBind());
+
+  ui::test::EventGenerator& generator(GetEventGenerator());
+  constexpr base::TimeDelta kTimeDelta = base::TimeDelta::FromMilliseconds(100);
+  constexpr int kNumScrollSteps = 4;
+
+  gfx::Point start = GetShelfWidget()->GetWindowBoundsInScreen().CenterPoint();
+  gfx::Vector2d delta;
+
+  // Swiping up more than the threshold should show the app list.
+  delta.set_y(ShelfLayoutManager::kAppListDragSnapToFullscreenThreshold + 10);
+  gfx::Point end = start - delta;
+  generator.GestureScrollSequence(start, end, kTimeDelta, kNumScrollSteps);
+  RunAllPendingInMessageLoop();
+  EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState());
+  EXPECT_EQ(1u, test_app_list_presenter.show_count());
+  EXPECT_GE(test_app_list_presenter.set_y_position_count(), 1u);
+  EXPECT_EQ(app_list::mojom::AppListState::FULLSCREEN_ALL_APPS,
+            test_app_list_presenter.app_list_state());
+
+  // Swiping up less or equal to the threshold should dismiss the app list.
+  delta.set_y(ShelfLayoutManager::kAppListDragSnapToFullscreenThreshold - 10);
+  end = start - delta;
+  // TODO(minch): investigate failure without EnableMaximizeMode again here.
+  // http://crbug.com/746481.
+  shell->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  generator.GestureScrollSequence(start, end, kTimeDelta, kNumScrollSteps);
+  RunAllPendingInMessageLoop();
+  EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState());
+  EXPECT_EQ(2u, test_app_list_presenter.show_count());
+  EXPECT_GE(test_app_list_presenter.set_y_position_count(), 1u);
+  EXPECT_EQ(app_list::mojom::AppListState::CLOSED,
+            test_app_list_presenter.app_list_state());
+
+  // Swiping down on the shelf should hide it.
+  end = start + delta;
+  generator.GestureScrollSequence(start, end, kTimeDelta, kNumScrollSteps);
+  EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState());
+  EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState());
+  EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, shelf->auto_hide_behavior());
+
+  // Swiping up should show the shelf but not the app list if shelf is hidden.
+  generator.GestureScrollSequence(end, start, kTimeDelta, kNumScrollSteps);
+  RunAllPendingInMessageLoop();
+  EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState());
+  EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_NEVER, shelf->auto_hide_behavior());
+  EXPECT_EQ(2u, test_app_list_presenter.show_count());
+  EXPECT_GE(test_app_list_presenter.set_y_position_count(), 1u);
+  EXPECT_EQ(app_list::mojom::AppListState::CLOSED,
+            test_app_list_presenter.app_list_state());
+
+  // Swiping down should hide the shelf.
+  generator.GestureScrollSequence(start, end, kTimeDelta, kNumScrollSteps);
+  EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState());
+  EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState());
+  EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, shelf->auto_hide_behavior());
+
+  // Minimize the visible window, the shelf should be shown if there are no
+  // visible windows, even in auto-hide mode.
+  widget->Minimize();
+  EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState());
+  EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState());
+  EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, shelf->auto_hide_behavior());
+
+  // Swiping up on the shelf in this state should open the app list.
+  delta.set_y(ShelfLayoutManager::kAppListDragSnapToFullscreenThreshold + 10);
+  end = start - delta;
+  generator.GestureScrollSequence(start, end, kTimeDelta, kNumScrollSteps);
+  RunAllPendingInMessageLoop();
+  EXPECT_EQ(3u, test_app_list_presenter.show_count());
+  EXPECT_EQ(app_list::mojom::AppListState::FULLSCREEN_ALL_APPS,
+            test_app_list_presenter.app_list_state());
+}
+
+TEST_F(ShelfLayoutManagerFullscreenAppListTest,
+       SwipingUpOnShelfInLaptopModeForFullscreenAppList) {
+  Shelf* shelf = GetPrimaryShelf();
+  EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM, shelf->alignment());
+  EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_NEVER, shelf->auto_hide_behavior());
+  EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState());
+
+  app_list::test::TestAppListPresenter test_app_list_presenter;
+  Shell::Get()->app_list()->SetAppListPresenter(
+      test_app_list_presenter.CreateInterfacePtrAndBind());
+
+  ui::test::EventGenerator& generator(GetEventGenerator());
+  constexpr base::TimeDelta kTimeDelta = base::TimeDelta::FromMilliseconds(100);
+  constexpr int kNumScrollSteps = 4;
+
+  gfx::Point start = GetShelfWidget()->GetWindowBoundsInScreen().CenterPoint();
+  gfx::Vector2d delta;
+
+  // Swiping up less than the close threshold should close the app list.
+  delta.set_y(ShelfLayoutManager::kAppListDragSnapToClosedThreshold - 10);
+  gfx::Point end = start - delta;
+  generator.GestureScrollSequence(start, end, kTimeDelta, kNumScrollSteps);
+  RunAllPendingInMessageLoop();
+  EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState());
+  EXPECT_EQ(1u, test_app_list_presenter.show_count());
+  EXPECT_GE(test_app_list_presenter.set_y_position_count(), 1u);
+  EXPECT_EQ(app_list::mojom::AppListState::CLOSED,
+            test_app_list_presenter.app_list_state());
+
+  // Swiping up more than the close threshold but less than peeking threshold
+  delta.set_y(ShelfLayoutManager::kAppListDragSnapToPeekingThreshold - 10);
+  end = start - delta;
+  generator.GestureScrollSequence(start, end, kTimeDelta, kNumScrollSteps);
+  RunAllPendingInMessageLoop();
+  EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState());
+  EXPECT_EQ(2u, test_app_list_presenter.show_count());
+  EXPECT_GE(test_app_list_presenter.set_y_position_count(), 1u);
+  EXPECT_EQ(app_list::mojom::AppListState::PEEKING,
+            test_app_list_presenter.app_list_state());
+
+  // Swiping up more than the peeking threshold should keep the app list at
+  // FULLSCREEN_ALL_APPS state.
+  Shell::Get()->DismissAppList();
+  delta.set_y(ShelfLayoutManager::kAppListDragSnapToPeekingThreshold + 10);
+  end = start - delta;
+  generator.GestureScrollSequence(start, end, kTimeDelta, kNumScrollSteps);
+  RunAllPendingInMessageLoop();
+  EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState());
+  EXPECT_EQ(3u, test_app_list_presenter.show_count());
+  EXPECT_GE(test_app_list_presenter.set_y_position_count(), 1u);
+  EXPECT_EQ(app_list::mojom::AppListState::FULLSCREEN_ALL_APPS,
+            test_app_list_presenter.app_list_state());
+}
+
 // Swiping on shelf when fullscreen app list is opened should have no effect.
-TEST_F(ShelfLayoutManagerTest, SwipingOnShelfIfFullscreenAppListOpened) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(
-      app_list::features::kEnableFullscreenAppList);
+TEST_F(ShelfLayoutManagerFullscreenAppListTest,
+       SwipingOnShelfIfFullscreenAppListOpened) {
   Shelf* shelf = GetPrimaryShelf();
   ShelfLayoutManager* layout_manager = GetShelfLayoutManager();
   aura::Window* root_window =
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc
index d5b8c8b6..7340aec 100644
--- a/ash/shelf/shelf_view.cc
+++ b/ash/shelf/shelf_view.cc
@@ -949,6 +949,9 @@
     // padding of the first gets properly transferred to the new first item.
     if (i && view->border())
       view->SetBorder(views::NullBorder());
+
+    if (view == GetAppListButton())
+      GetAppListButton()->OnBoundsAnimationStarted();
   }
   overflow_button_->SetBoundsRect(overflow_bounds);
 }
@@ -1893,6 +1896,9 @@
       snap_back_from_rip_off_view_ = nullptr;
     }
   }
+
+  if (GetAppListButton())
+    GetAppListButton()->OnBoundsAnimationFinished();
 }
 
 bool ShelfView::IsRepostEvent(const ui::Event& event) {
diff --git a/ash/shelf/shelf_view_unittest.cc b/ash/shelf/shelf_view_unittest.cc
index 66d96b92..5a1a49c51 100644
--- a/ash/shelf/shelf_view_unittest.cc
+++ b/ash/shelf/shelf_view_unittest.cc
@@ -2568,6 +2568,40 @@
                           views::InkDropState::DEACTIVATED));
 }
 
+// Ensure the app list button ink drop is disabled during bounds animations.
+// TODO(crbug.com/758402): Update ink drop bounds with app list button bounds.
+TEST_F(ShelfViewInkDropTest, AppListButtonInkDropDisabledOnAnimations) {
+  InitAppListButtonInkDrop();
+
+  // Display the app list.
+  TestAppListPresenterImpl app_list_presenter_impl;
+  app_list_presenter_impl.ShowAndRunLoop(GetPrimaryDisplay().id());
+  EXPECT_EQ(views::InkDropState::ACTIVATED,
+            app_list_button_ink_drop_->GetTargetInkDropState());
+  EXPECT_THAT(app_list_button_ink_drop_->GetAndResetRequestedStates(),
+              ElementsAre(views::InkDropState::ACTIVATED));
+
+  // The ink drop should be hidden during the animation to enter tablet mode.
+  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  EXPECT_THAT(app_list_button_ink_drop_->GetAndResetRequestedStates(),
+              ElementsAre(views::InkDropState::DEACTIVATED));
+  test_api_->RunMessageLoopUntilAnimationsDone();
+  EXPECT_EQ(views::InkDropState::ACTIVATED,
+            app_list_button_ink_drop_->GetTargetInkDropState());
+  EXPECT_THAT(app_list_button_ink_drop_->GetAndResetRequestedStates(),
+              ElementsAre(views::InkDropState::ACTIVATED));
+
+  // The ink drop should be hidden during the animation to exit tablet mode.
+  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  EXPECT_THAT(app_list_button_ink_drop_->GetAndResetRequestedStates(),
+              ElementsAre(views::InkDropState::DEACTIVATED));
+  test_api_->RunMessageLoopUntilAnimationsDone();
+  EXPECT_EQ(views::InkDropState::ACTIVATED,
+            app_list_button_ink_drop_->GetTargetInkDropState());
+  EXPECT_THAT(app_list_button_ink_drop_->GetAndResetRequestedStates(),
+              ElementsAre(views::InkDropState::ACTIVATED));
+}
+
 namespace {
 
 // Test fixture to run app list button ink drop tests for both mouse and touch
diff --git a/ash/shell.cc b/ash/shell.cc
index cccf773..0014507d 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -431,10 +431,7 @@
 }
 
 PrefService* Shell::GetLocalStatePrefService() const {
-  if (shell_port_->GetAshConfig() == Config::MASH)
-    return local_state_mash_.get();
-
-  return local_state_non_mash_;
+  return local_state_.get();
 }
 
 WebNotificationTray* Shell::GetWebNotificationTray() {
@@ -507,13 +504,6 @@
                       .id());
 }
 
-void Shell::UpdateAppListYPositionAndOpacity(int y_position_in_screen,
-                                             float app_list_background_opacity,
-                                             bool is_end_gesture) {
-  app_list_->UpdateYPositionAndOpacity(
-      y_position_in_screen, app_list_background_opacity, is_end_gesture);
-}
-
 void Shell::DismissAppList() {
   app_list_->Dismiss();
 }
@@ -600,15 +590,6 @@
   g_is_browser_process_with_mash = true;
 }
 
-void Shell::SetLocalStatePrefService(PrefService* local_state) {
-  DCHECK(GetAshConfig() != Config::MASH);
-  DCHECK(local_state);
-  local_state_non_mash_ = local_state;
-
-  for (auto& observer : shell_observers_)
-    observer.OnLocalStatePrefServiceInitialized(local_state_non_mash_);
-}
-
 void Shell::NotifyAppListVisibilityChanged(bool visible,
                                            aura::Window* root_window) {
   for (auto& observer : shell_observers_)
@@ -630,6 +611,11 @@
     observer.OnVoiceInteractionContextEnabled(enabled);
 }
 
+void Shell::NotifyVoiceInteractionSetupCompleted() {
+  for (auto& observer : shell_observers_)
+    observer.OnVoiceInteractionSetupCompleted();
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Shell, private:
 
@@ -872,8 +858,7 @@
   // NightLightController depeneds on the PrefService and must be destructed
   // before it. crbug.com/724231.
   night_light_controller_ = nullptr;
-  local_state_mash_.reset();
-  local_state_non_mash_ = nullptr;
+  local_state_.reset();
   shell_delegate_.reset();
 
   for (auto& observer : shell_observers_)
@@ -894,7 +879,7 @@
   wallpaper_delegate_ = shell_delegate_->CreateWallpaperDelegate();
 
   // Connector can be null in tests.
-  if (config == Config::MASH && shell_delegate_->GetShellConnector()) {
+  if (shell_delegate_->GetShellConnector()) {
     // Connect to local state prefs now, but wait for an active user before
     // connecting to the profile pref service. The login screen has a temporary
     // user profile that is not associated with a real user.
@@ -1318,13 +1303,16 @@
 
 void Shell::OnLocalStatePrefServiceInitialized(
     std::unique_ptr<::PrefService> pref_service) {
-  DCHECK(GetAshConfig() == Config::MASH);
+  DCHECK(!local_state_);
   // |pref_service| is null if can't connect to Chrome (as happens when
   // running mash outside of chrome --mash and chrome isn't built).
-  local_state_mash_ = std::move(pref_service);
+  if (!pref_service)
+    return;
+
+  local_state_ = std::move(pref_service);
 
   for (auto& observer : shell_observers_)
-    observer.OnLocalStatePrefServiceInitialized(local_state_mash_.get());
+    observer.OnLocalStatePrefServiceInitialized(local_state_.get());
 }
 
 }  // namespace ash
diff --git a/ash/shell.h b/ash/shell.h
index e414fcb..6af5b1b 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -537,16 +537,11 @@
   void AddShellObserver(ShellObserver* observer);
   void RemoveShellObserver(ShellObserver* observer);
 
+  // TODO(minch), move applist related functions to AppList.
+  // http://crbug.com/759909.
   // Shows the app list on the active root window.
   void ShowAppList(app_list::AppListShowSource toggle_method);
 
-  // Updates y position and opacity of app list. |is_end_gesture| means it is
-  // the end of the gesture dragging of app list from shelf and should restore
-  // the opacity of the app list.
-  void UpdateAppListYPositionAndOpacity(int y_position_in_screen,
-                                        float app_list_background_opacity,
-                                        bool is_end_gesture);
-
   // Dismisses the app list.
   void DismissAppList();
 
@@ -605,9 +600,6 @@
   // Used to provide better error messages for Shell::Get() under mash.
   static void SetIsBrowserProcessWithMash();
 
-  // Used when Chrome owns the pref service (not mash).
-  void SetLocalStatePrefService(PrefService* local_state);
-
   void NotifyAppListVisibilityChanged(bool visible, aura::Window* root_window);
 
   // TODO(kaznacheev) Move voice interaction related methods to a separate
@@ -618,11 +610,14 @@
 
   void NotifyVoiceInteractionContextEnabled(bool enabled);
 
+  void NotifyVoiceInteractionSetupCompleted();
+
  private:
   FRIEND_TEST_ALL_PREFIXES(ExtendedDesktopTest, TestCursor);
   FRIEND_TEST_ALL_PREFIXES(WindowManagerTest, MouseEventCursors);
   FRIEND_TEST_ALL_PREFIXES(WindowManagerTest, TransformActivate);
   friend class AcceleratorControllerTest;
+  friend class AshTestHelper;
   friend class RootWindowController;
   friend class ScopedRootWindowForNewWindows;
   friend class ShellTestApi;
@@ -725,13 +720,7 @@
   std::unique_ptr<::wm::VisibilityController> visibility_controller_;
   std::unique_ptr<::wm::WindowModalityController> window_modality_controller_;
   std::unique_ptr<app_list::AppList> app_list_;
-
-  // Used in non-mash. Owned by chrome.
-  PrefService* local_state_non_mash_ = nullptr;
-
-  // Used in mash.
-  std::unique_ptr<PrefService> local_state_mash_;
-
+  std::unique_ptr<PrefService> local_state_;
   std::unique_ptr<views::corewm::TooltipController> tooltip_controller_;
   LinkHandlerModelFactory* link_handler_model_factory_;
   std::unique_ptr<PowerButtonController> power_button_controller_;
diff --git a/ash/shell/example_app_list_presenter.cc b/ash/shell/example_app_list_presenter.cc
index e8d4e3ea..70e90a1 100644
--- a/ash/shell/example_app_list_presenter.cc
+++ b/ash/shell/example_app_list_presenter.cc
@@ -72,8 +72,10 @@
 
 void ExampleAppListPresenter::UpdateYPositionAndOpacity(
     int new_y_position,
-    float background_opacity,
-    bool is_end_gesture) {}
+    float background_opacity) {}
+
+void ExampleAppListPresenter::EndDragFromShelf(
+    app_list::mojom::AppListState app_list_state) {}
 
 }  // namespace shell
 }  // namespace ash
diff --git a/ash/shell/example_app_list_presenter.h b/ash/shell/example_app_list_presenter.h
index 723d963..599b6fb 100644
--- a/ash/shell/example_app_list_presenter.h
+++ b/ash/shell/example_app_list_presenter.h
@@ -29,8 +29,8 @@
   void StartVoiceInteractionSession() override;
   void ToggleVoiceInteractionSession() override;
   void UpdateYPositionAndOpacity(int new_y_position,
-                                 float background_opacity,
-                                 bool is_end_gesture) override;
+                                 float background_opacity) override;
+  void EndDragFromShelf(app_list::mojom::AppListState app_list_state) override;
 
  private:
   mojo::Binding<app_list::mojom::AppListPresenter> binding_;
diff --git a/ash/shell_observer.h b/ash/shell_observer.h
index 9636de1..ed2935c 100644
--- a/ash/shell_observer.h
+++ b/ash/shell_observer.h
@@ -82,6 +82,9 @@
   // the "context" (text and graphic content that is currently on screen).
   virtual void OnVoiceInteractionContextEnabled(bool enabled) {}
 
+  // Called when voice interaction setup flow completed.
+  virtual void OnVoiceInteractionSetupCompleted() {}
+
   // Called at the end of Shell::Init.
   virtual void OnShellInitialized() {}
 
diff --git a/ash/shell_unittest.cc b/ash/shell_unittest.cc
index d418c79..12d10e4 100644
--- a/ash/shell_unittest.cc
+++ b/ash/shell_unittest.cc
@@ -553,46 +553,17 @@
   window_->Init(ui::LAYER_NOT_DRAWN);
 }
 
-// Tests the local state code path used with Config::CLASSIC and Config::MUS.
-class ShellLocalStateTestNonMash : public NoSessionAshTestBase {
+// Tests the local state code path.
+class ShellLocalStateTest : public AshTestBase {
  public:
-  ShellLocalStateTestNonMash() = default;
-  ~ShellLocalStateTestNonMash() override = default;
-
-  // Must outlive Shell.
-  TestingPrefServiceSimple local_state_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ShellLocalStateTestNonMash);
+  ShellLocalStateTest() { disable_provide_local_state(); }
 };
 
-TEST_F(ShellLocalStateTestNonMash, LocalState) {
-  if (Shell::GetAshConfig() == Config::MASH)
-    return;
-
+TEST_F(ShellLocalStateTest, LocalState) {
   TestShellObserver observer;
   Shell::Get()->AddShellObserver(&observer);
 
-  // In classic ash, chrome calls into ash to set up local state.
-  Shell::RegisterLocalStatePrefs(local_state_.registry());
-  Shell::Get()->SetLocalStatePrefService(&local_state_);
-  EXPECT_EQ(&local_state_, observer.last_local_state_);
-  EXPECT_EQ(&local_state_, Shell::Get()->GetLocalStatePrefService());
-
-  Shell::Get()->RemoveShellObserver(&observer);
-}
-
-// Tests the local state code path used with Config::MASH.
-using ShellLocalStateTestMash = ShellTest;
-
-TEST_F(ShellLocalStateTestMash, LocalState) {
-  if (Shell::GetAshConfig() != Config::MASH)
-    return;
-
-  TestShellObserver observer;
-  Shell::Get()->AddShellObserver(&observer);
-
-  // In mash, prefs service wrapper code creates a PrefService.
+  // Prefs service wrapper code creates a PrefService.
   std::unique_ptr<TestingPrefServiceSimple> local_state =
       base::MakeUnique<TestingPrefServiceSimple>();
   Shell::RegisterLocalStatePrefs(local_state->registry());
diff --git a/ash/system/palette/palette_tray.cc b/ash/system/palette/palette_tray.cc
index d20e84a3..d663f70 100644
--- a/ash/system/palette/palette_tray.cc
+++ b/ash/system/palette/palette_tray.cc
@@ -242,10 +242,6 @@
     PrefService* pref_service) {
   local_state_pref_service_ = pref_service;
 
-  // May be null in mash_unittests where there is no mojo pref service.
-  if (!local_state_pref_service_)
-    return;
-
   // If a device has an internal stylus or the flag to force stylus is set, mark
   // the has seen stylus flag as true since we know the user has a stylus.
   if (palette_utils::HasInternalStylus() ||
diff --git a/ash/system/palette/palette_tray_unittest.cc b/ash/system/palette/palette_tray_unittest.cc
index 031d325..868f386 100644
--- a/ash/system/palette/palette_tray_unittest.cc
+++ b/ash/system/palette/palette_tray_unittest.cc
@@ -23,7 +23,7 @@
 #include "base/command_line.h"
 #include "base/memory/ptr_util.h"
 #include "chromeos/chromeos_switches.h"
-#include "components/prefs/testing_pref_service.h"
+#include "components/prefs/pref_service.h"
 #include "components/session_manager/session_manager_types.h"
 #include "ui/events/devices/device_data_manager.h"
 #include "ui/events/devices/touchscreen_device.h"
@@ -42,11 +42,9 @@
     base::CommandLine::ForCurrentProcess()->AppendSwitch(
         switches::kAshEnablePaletteOnAllDisplays);
 
-    AshTestBase::SetUp();
-
     palette_utils::SetHasStylusInputForTesting();
 
-    Shell::RegisterLocalStatePrefs(pref_service_.registry());
+    AshTestBase::SetUp();
 
     palette_tray_ =
         StatusAreaWidgetTestHelper::GetStatusAreaWidget()->palette_tray();
@@ -59,7 +57,6 @@
     // from the palette delegate. (It was initialized without the delegate in
     // AshTestBase::SetUp()).
     palette_tray_->Initialize();
-    palette_tray_->OnLocalStatePrefServiceInitialized(&pref_service_);
   }
 
   // Performs a tap on the palette tray button.
@@ -74,8 +71,11 @@
     return static_cast<TestPaletteDelegate*>(Shell::Get()->palette_delegate());
   }
 
+  PrefService* pref_service() {
+    return Shell::Get()->GetLocalStatePrefService();
+  }
+
   PaletteTray* palette_tray_ = nullptr;  // not owned
-  TestingPrefServiceSimple pref_service_;
 
   std::unique_ptr<PaletteTray::TestApi> test_api_;
 
@@ -101,7 +101,7 @@
 // should become visible after seeing a stylus event.
 TEST_F(PaletteTrayTest, PaletteTrayVisibleAfterStylusSeen) {
   ASSERT_FALSE(palette_tray_->visible());
-  ASSERT_FALSE(pref_service_.GetBoolean(prefs::kHasSeenStylus));
+  ASSERT_FALSE(pref_service()->GetBoolean(prefs::kHasSeenStylus));
   ASSERT_TRUE(test_api_->IsStylusWatcherActive());
 
   // Send a stylus event.
@@ -120,7 +120,7 @@
 // visible.
 TEST_F(PaletteTrayTest, StylusSeenPrefInitiallySet) {
   ASSERT_FALSE(palette_tray_->visible());
-  pref_service_.SetBoolean(prefs::kHasSeenStylus, true);
+  pref_service()->SetBoolean(prefs::kHasSeenStylus, true);
 
   EXPECT_TRUE(palette_tray_->visible());
   EXPECT_FALSE(test_api_->IsStylusWatcherActive());
diff --git a/ash/system/system_notifier.h b/ash/system/system_notifier.h
index e6fa170..4239ae5 100644
--- a/ash/system/system_notifier.h
+++ b/ash/system/system_notifier.h
@@ -64,7 +64,8 @@
 // will be ignored.
 // TODO(tetsui): Remove this function when new style notification becomes
 // default.
-std::unique_ptr<message_center::Notification> CreateSystemNotification(
+ASH_EXPORT std::unique_ptr<message_center::Notification>
+CreateSystemNotification(
     message_center::NotificationType type,
     const std::string& id,
     const base::string16& title,
diff --git a/ash/system/tray_caps_lock.cc b/ash/system/tray_caps_lock.cc
index 6d55f23..c696a7d 100644
--- a/ash/system/tray_caps_lock.cc
+++ b/ash/system/tray_caps_lock.cc
@@ -5,6 +5,7 @@
 #include "ash/system/tray_caps_lock.h"
 
 #include "ash/accessibility_delegate.h"
+#include "ash/ime/ime_controller.h"
 #include "ash/metrics/user_metrics_recorder.h"
 #include "ash/public/cpp/config.h"
 #include "ash/resources/vector_icons/vector_icons.h"
@@ -22,7 +23,6 @@
 #include "components/prefs/pref_service.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/base/ime/chromeos/ime_keyboard.h"
-#include "ui/base/ime/chromeos/input_method_manager.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/chromeos/events/pref_names.h"
@@ -47,12 +47,8 @@
 
 const char kCapsLockNotificationId[] = "capslock";
 
-bool CapsLockIsEnabled() {
-  chromeos::input_method::InputMethodManager* ime =
-      chromeos::input_method::InputMethodManager::Get();
-  return (ime && ime->GetImeKeyboard())
-             ? ime->GetImeKeyboard()->CapsLockIsEnabled()
-             : false;
+bool IsCapsLockEnabled() {
+  return Shell::Get()->ime_controller()->IsCapsLockEnabled();
 }
 
 bool IsSearchKeyMappedToCapsLock() {
@@ -61,6 +57,12 @@
   // Null early in mash startup.
   if (!prefs)
     return false;
+
+  // This pref value is not registered in tests.
+  // TODO(crbug/760406): register this pref in tests and remove this check.
+  if (!prefs->FindPreference(prefs::kLanguageRemapSearchKeyTo))
+    return false;
+
   // Don't bother to observe for the pref changing because the system tray
   // menu is rebuilt every time it is opened and the user has to close the
   // menu to open settings to change the pref. It's not worth the complexity
@@ -175,15 +177,11 @@
 
   // ActionableView:
   bool PerformAction(const ui::Event& event) override {
-    chromeos::input_method::ImeKeyboard* keyboard =
-        chromeos::input_method::InputMethodManager::Get()->GetImeKeyboard();
-    if (keyboard) {
-      Shell::Get()->metrics()->RecordUserMetricsAction(
-          keyboard->CapsLockIsEnabled()
-              ? UMA_STATUS_AREA_CAPS_LOCK_DISABLED_BY_CLICK
-              : UMA_STATUS_AREA_CAPS_LOCK_ENABLED_BY_CLICK);
-      keyboard->SetCapsLockEnabled(!keyboard->CapsLockIsEnabled());
-    }
+    bool new_state = !IsCapsLockEnabled();
+    Shell::Get()->ime_controller()->SetCapsLockFromTray(new_state);
+    Shell::Get()->metrics()->RecordUserMetricsAction(
+        new_state ? UMA_STATUS_AREA_CAPS_LOCK_ENABLED_BY_CLICK
+                  : UMA_STATUS_AREA_CAPS_LOCK_DISABLED_BY_CLICK);
     return true;
   }
 
@@ -199,19 +197,13 @@
 TrayCapsLock::TrayCapsLock(SystemTray* system_tray)
     : TrayImageItem(system_tray, kSystemTrayCapsLockIcon, UMA_CAPS_LOCK),
       default_(nullptr),
-      caps_lock_enabled_(CapsLockIsEnabled()),
+      caps_lock_enabled_(IsCapsLockEnabled()),
       message_shown_(false) {
-  chromeos::input_method::InputMethodManager* ime =
-      chromeos::input_method::InputMethodManager::Get();
-  if (ime && ime->GetImeKeyboard())
-    ime->GetImeKeyboard()->AddObserver(this);
+  Shell::Get()->ime_controller()->AddObserver(this);
 }
 
 TrayCapsLock::~TrayCapsLock() {
-  chromeos::input_method::InputMethodManager* ime =
-      chromeos::input_method::InputMethodManager::Get();
-  if (ime && ime->GetImeKeyboard())
-    ime->GetImeKeyboard()->RemoveObserver(this);
+  Shell::Get()->ime_controller()->RemoveObserver(this);
 }
 
 // static
@@ -250,10 +242,8 @@
   }
 }
 
-void TrayCapsLock::OnLayoutChanging(const std::string& layout_name) {}
-
 bool TrayCapsLock::GetInitialVisibility() {
-  return CapsLockIsEnabled();
+  return IsCapsLockEnabled();
 }
 
 views::View* TrayCapsLock::CreateDefaultView(LoginStatus status) {
diff --git a/ash/system/tray_caps_lock.h b/ash/system/tray_caps_lock.h
index 18086ce..939039652 100644
--- a/ash/system/tray_caps_lock.h
+++ b/ash/system/tray_caps_lock.h
@@ -5,10 +5,9 @@
 #ifndef ASH_SYSTEM_TRAY_CAPS_LOCK_H_
 #define ASH_SYSTEM_TRAY_CAPS_LOCK_H_
 
+#include "ash/ime/ime_controller.h"
 #include "ash/system/tray/tray_image_item.h"
 #include "base/macros.h"
-#include "ui/base/ime/chromeos/ime_keyboard.h"
-#include "ui/events/event_handler.h"
 
 class PrefRegistrySimple;
 
@@ -20,17 +19,15 @@
 class CapsLockDefaultView;
 
 // Shows a status area icon and a system tray menu item when caps lock is on.
-class TrayCapsLock : public TrayImageItem,
-                     public chromeos::input_method::ImeKeyboard::Observer {
+class TrayCapsLock : public TrayImageItem, public ImeController::Observer {
  public:
   explicit TrayCapsLock(SystemTray* system_tray);
   ~TrayCapsLock() override;
 
   static void RegisterForeignPrefs(PrefRegistrySimple* registry);
 
-  // Overridden from chromeos::input_method::ImeKeyboard::Observer:
+  // Overridden from ImeController::Observer:
   void OnCapsLockChanged(bool enabled) override;
-  void OnLayoutChanging(const std::string& layout_name) override;
 
   // Overridden from TrayImageItem.
   bool GetInitialVisibility() override;
diff --git a/ash/system/tray_caps_lock_unittest.cc b/ash/system/tray_caps_lock_unittest.cc
index f98f77e..8e91510 100644
--- a/ash/system/tray_caps_lock_unittest.cc
+++ b/ash/system/tray_caps_lock_unittest.cc
@@ -11,6 +11,7 @@
 #include "ash/test/ash_test_base.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
+#include "ui/base/ime/chromeos/ime_keyboard.h"
 #include "ui/chromeos/events/pref_names.h"
 
 namespace ash {
diff --git a/ash/test/ash_test_base.cc b/ash/test/ash_test_base.cc
index 8b85878..b773683 100644
--- a/ash/test/ash_test_base.cc
+++ b/ash/test/ash_test_base.cc
@@ -147,7 +147,7 @@
   // default state.
   shell::ToplevelWindow::ClearSavedStateForTest();
 
-  ash_test_helper_->SetUp(start_session_);
+  ash_test_helper_->SetUp(start_session_, provide_local_state_);
 
   Shell::GetPrimaryRootWindow()->Show();
   Shell::GetPrimaryRootWindow()->GetHost()->Show();
diff --git a/ash/test/ash_test_base.h b/ash/test/ash_test_base.h
index 3d1cf293..37354da9 100644
--- a/ash/test/ash_test_base.h
+++ b/ash/test/ash_test_base.h
@@ -167,6 +167,7 @@
   static display::Display::Rotation GetCurrentInternalDisplayRotation();
 
   void set_start_session(bool start_session) { start_session_ = start_session; }
+  void disable_provide_local_state() { provide_local_state_ = false; }
 
   AshTestHelper* ash_test_helper() { return ash_test_helper_.get(); }
 
@@ -221,6 +222,9 @@
   bool teardown_called_;
   // |SetUp()| doesn't activate session if this is set to false.
   bool start_session_;
+  // |SetUp()| doesn't inject local-state PrefService into Shell if this is
+  // set to false.
+  bool provide_local_state_ = true;
   std::unique_ptr<AshTestEnvironment> ash_test_environment_;
   std::unique_ptr<AshTestHelper> ash_test_helper_;
   std::unique_ptr<ui::test::EventGenerator> event_generator_;
diff --git a/ash/test/ash_test_helper.cc b/ash/test/ash_test_helper.cc
index 291559e2..a54bfdd 100644
--- a/ash/test/ash_test_helper.cc
+++ b/ash/test/ash_test_helper.cc
@@ -31,6 +31,7 @@
 #include "chromeos/cryptohome/system_salt_getter.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/network/network_handler.h"
+#include "components/prefs/testing_pref_service.h"
 #include "device/bluetooth/bluetooth_adapter_factory.h"
 #include "device/bluetooth/dbus/bluez_dbus_manager.h"
 #include "services/ui/public/cpp/input_devices/input_device_client.h"
@@ -73,7 +74,7 @@
 
 AshTestHelper::~AshTestHelper() {}
 
-void AshTestHelper::SetUp(bool start_session) {
+void AshTestHelper::SetUp(bool start_session, bool provide_local_state) {
   command_line_ = base::MakeUnique<base::test::ScopedCommandLine>();
   // TODO(jamescook): Can we do this without changing command line?
   // Use the origin (1,1) so that it doesn't over
@@ -161,12 +162,19 @@
       std::unique_ptr<aura::InputStateLookup>());
 
   Shell* shell = Shell::Get();
+  if (provide_local_state) {
+    auto pref_service = base::MakeUnique<TestingPrefServiceSimple>();
+    Shell::RegisterLocalStatePrefs(pref_service->registry());
+    Shell::Get()->OnLocalStatePrefServiceInitialized(std::move(pref_service));
+  }
+
   session_controller_client_.reset(
       new TestSessionControllerClient(shell->session_controller()));
   session_controller_client_->InitializeAndBind();
 
-  if (start_session)
+  if (start_session) {
     session_controller_client_->CreatePredefinedUserSessions(1);
+  }
 
   // Tests that change the display configuration generally don't care about
   // the notifications and the popup UI can interfere with things like
diff --git a/ash/test/ash_test_helper.h b/ash/test/ash_test_helper.h
index 566c61e..12c8da35 100644
--- a/ash/test/ash_test_helper.h
+++ b/ash/test/ash_test_helper.h
@@ -70,7 +70,9 @@
 
   // Creates the ash::Shell and performs associated initialization.  Set
   // |start_session| to true if the user should log in before the test is run.
-  void SetUp(bool start_session);
+  // Set |provide_local_state| to true to inject local-state PrefService into
+  // the Shell before the test is run.
+  void SetUp(bool start_session, bool provide_local_state = true);
 
   // Destroys the ash::Shell and performs associated cleanup.
   void TearDown();
diff --git a/ash/touch/touch_uma.cc b/ash/touch/touch_uma.cc
index 8400cd6..3ae40dc9c 100644
--- a/ash/touch/touch_uma.cc
+++ b/ash/touch/touch_uma.cc
@@ -4,9 +4,9 @@
 
 #include "ash/touch/touch_uma.h"
 
-#include "ash/metrics/user_metrics_recorder.h"
 #include "ash/shell.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/metrics/user_metrics.h"
 #include "base/optional.h"
 #include "base/strings/stringprintf.h"
 #include "ui/aura/env.h"
@@ -110,7 +110,7 @@
       kBucketCountForLocation, kBucketCountForLocation + 1);
 
   if (event.type() == ui::ET_TOUCH_PRESSED) {
-    Shell::Get()->metrics()->RecordUserMetricsAction(UMA_TOUCHSCREEN_TAP_DOWN);
+    base::RecordAction(base::UserMetricsAction("Touchscreen_Down"));
 
     if (details->last_release_time_) {
       // Measuring the interval between a touch-release and the next
diff --git a/ash/wallpaper/wallpaper_controller.cc b/ash/wallpaper/wallpaper_controller.cc
index 4aa97499..855b9a9f 100644
--- a/ash/wallpaper/wallpaper_controller.cc
+++ b/ash/wallpaper/wallpaper_controller.cc
@@ -57,10 +57,8 @@
 // Caches color calculation results in local state pref service.
 void CacheProminentColors(const std::vector<SkColor>& colors,
                           const std::string& current_location) {
-  // Local state can be null in tests.
-  // TODO(crbug.com/751191): Remove the check for Mash.
-  if (Shell::GetAshConfig() == Config::MASH ||
-      !Shell::Get()->GetLocalStatePrefService()) {
+  // Local state can be null during startup.
+  if (!Shell::Get()->GetLocalStatePrefService()) {
     return;
   }
   DictionaryPrefUpdate wallpaper_colors_update(
@@ -78,10 +76,8 @@
     const std::string& current_location) {
   base::Optional<std::vector<SkColor>> cached_colors_out;
   const base::ListValue* prominent_colors = nullptr;
-  // Local state can be null in tests.
-  // TODO(crbug.com/751191): Remove the check for Mash.
-  if (Shell::GetAshConfig() == Config::MASH ||
-      !Shell::Get()->GetLocalStatePrefService() ||
+  // Local state can be null during startup.
+  if (!Shell::Get()->GetLocalStatePrefService() ||
       !Shell::Get()
            ->GetLocalStatePrefService()
            ->GetDictionary(prefs::kWallpaperColors)
@@ -189,7 +185,7 @@
 // static
 void WallpaperController::RegisterLocalStatePrefs(
     PrefRegistrySimple* registry) {
-  registry->RegisterDictionaryPref(prefs::kWallpaperColors);
+  registry->RegisterForeignPref(prefs::kWallpaperColors);
 }
 
 void WallpaperController::BindRequest(
@@ -299,6 +295,11 @@
   InstallDesktopController(root_window);
 }
 
+void WallpaperController::OnLocalStatePrefServiceInitialized(
+    PrefService* pref_service) {
+  CalculateWallpaperColors();
+}
+
 void WallpaperController::OnSessionStateChanged(
     session_manager::SessionState state) {
   CalculateWallpaperColors();
diff --git a/ash/wallpaper/wallpaper_controller.h b/ash/wallpaper/wallpaper_controller.h
index 895d8b1..410e32a 100644
--- a/ash/wallpaper/wallpaper_controller.h
+++ b/ash/wallpaper/wallpaper_controller.h
@@ -102,6 +102,7 @@
 
   // ShellObserver:
   void OnRootWindowAdded(aura::Window* root_window) override;
+  void OnLocalStatePrefServiceInitialized(PrefService* pref_service) override;
 
   // SessionObserver:
   void OnSessionStateChanged(session_manager::SessionState state) override;
diff --git a/ash/wm/gestures/overview_gesture_handler.cc b/ash/wm/gestures/overview_gesture_handler.cc
index 938bb97c..ac1bcc7c 100644
--- a/ash/wm/gestures/overview_gesture_handler.cc
+++ b/ash/wm/gestures/overview_gesture_handler.cc
@@ -4,9 +4,9 @@
 
 #include "ash/wm/gestures/overview_gesture_handler.h"
 
-#include "ash/metrics/user_metrics_recorder.h"
 #include "ash/shell.h"
 #include "ash/wm/overview/window_selector_controller.h"
+#include "base/metrics/user_metrics.h"
 #include "ui/events/event.h"
 #include "ui/events/event_constants.h"
 
@@ -66,8 +66,7 @@
 
   // Reset scroll amount on toggling.
   scroll_x_ = scroll_y_ = 0;
-  Shell::Get()->metrics()->RecordUserMetricsAction(
-      UMA_TOUCHPAD_GESTURE_OVERVIEW);
+  base::RecordAction(base::UserMetricsAction("Touchpad_Gesture_Overview"));
   if (window_selector_controller->IsSelecting() &&
       window_selector_controller->AcceptSelection()) {
     return true;
diff --git a/ash/wm/panels/panel_window_event_handler.cc b/ash/wm/panels/panel_window_event_handler.cc
index bb129a89a..2ca6d3b3 100644
--- a/ash/wm/panels/panel_window_event_handler.cc
+++ b/ash/wm/panels/panel_window_event_handler.cc
@@ -4,10 +4,9 @@
 
 #include "ash/wm/panels/panel_window_event_handler.h"
 
-#include "ash/metrics/user_metrics_recorder.h"
-#include "ash/shell.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
+#include "base/metrics/user_metrics.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_delegate.h"
 #include "ui/base/hit_test.h"
@@ -25,8 +24,7 @@
       event->flags() & ui::EF_IS_DOUBLE_CLICK &&
       event->IsOnlyLeftMouseButton() &&
       wm::GetNonClientComponent(target, event->location()) == HTCAPTION) {
-    Shell::Get()->metrics()->RecordUserMetricsAction(
-        UMA_PANEL_MINIMIZE_CAPTION_CLICK);
+    base::RecordAction(base::UserMetricsAction("Panel_Minimize_Caption_Click"));
     wm::GetWindowState(target)->Minimize();
     event->StopPropagation();
     return;
@@ -38,8 +36,8 @@
   if (!event->handled() && event->type() == ui::ET_GESTURE_TAP &&
       event->details().tap_count() == 2 &&
       wm::GetNonClientComponent(target, event->location()) == HTCAPTION) {
-    Shell::Get()->metrics()->RecordUserMetricsAction(
-        UMA_PANEL_MINIMIZE_CAPTION_GESTURE);
+    base::RecordAction(
+        base::UserMetricsAction("Panel_Minimize_Caption_Gesture"));
     wm::GetWindowState(target)->Minimize();
     event->StopPropagation();
     return;
diff --git a/ash/wm/system_gesture_event_filter.cc b/ash/wm/system_gesture_event_filter.cc
index 9dcfd92..8470484 100644
--- a/ash/wm/system_gesture_event_filter.cc
+++ b/ash/wm/system_gesture_event_filter.cc
@@ -4,10 +4,10 @@
 
 #include "ash/wm/system_gesture_event_filter.h"
 
-#include "ash/metrics/user_metrics_recorder.h"
-#include "ash/shell.h"
 #include "ash/touch/touch_uma.h"
 #include "ash/wm/gestures/overview_gesture_handler.h"
+#include "base/metrics/user_metrics.h"
+#include "ui/aura/window.h"
 #include "ui/base/touch/touch_device.h"
 #include "ui/events/event.h"
 #include "ui/events/event_constants.h"
@@ -23,7 +23,7 @@
   if (event->type() == ui::ET_MOUSE_PRESSED &&
       ui::GetTouchScreensAvailability() ==
           ui::TouchScreensAvailability::ENABLED) {
-    Shell::Get()->metrics()->RecordUserMetricsAction(UMA_MOUSE_DOWN);
+    base::RecordAction(base::UserMetricsAction("Mouse_Down"));
   }
 }
 
@@ -36,12 +36,12 @@
 
 void SystemGestureEventFilter::OnTouchEvent(ui::TouchEvent* event) {
   aura::Window* target = static_cast<aura::Window*>(event->target());
-  ash::TouchUMA::GetInstance()->RecordTouchEvent(target, *event);
+  TouchUMA::GetInstance()->RecordTouchEvent(target, *event);
 }
 
 void SystemGestureEventFilter::OnGestureEvent(ui::GestureEvent* event) {
   aura::Window* target = static_cast<aura::Window*>(event->target());
-  ash::TouchUMA::GetInstance()->RecordGestureEvent(target, *event);
+  TouchUMA::GetInstance()->RecordGestureEvent(target, *event);
 }
 
 }  // namespace ash
diff --git a/ash/wm/tablet_mode/tablet_mode_controller.cc b/ash/wm/tablet_mode/tablet_mode_controller.cc
index 72f56a6..7d33ed6 100644
--- a/ash/wm/tablet_mode/tablet_mode_controller.cc
+++ b/ash/wm/tablet_mode/tablet_mode_controller.cc
@@ -7,7 +7,6 @@
 #include <utility>
 
 #include "ash/ash_switches.h"
-#include "ash/metrics/user_metrics_recorder.h"
 #include "ash/shell.h"
 #include "ash/shell_delegate.h"
 #include "ash/wm/tablet_mode/scoped_disable_internal_mouse_and_keyboard.h"
@@ -17,6 +16,7 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/metrics/user_metrics.h"
 #include "base/time/default_tick_clock.h"
 #include "base/time/tick_clock.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
@@ -127,8 +127,7 @@
       scoped_session_observer_(this),
       weak_factory_(this) {
   Shell::Get()->AddShellObserver(this);
-  Shell::Get()->metrics()->RecordUserMetricsAction(
-      UMA_MAXIMIZE_MODE_INITIALLY_DISABLED);
+  base::RecordAction(base::UserMetricsAction("Touchview_Initially_Disabled"));
 
   // TODO(jonross): Do not create TabletModeController if the flag is
   // unavailable. This will require refactoring
@@ -172,7 +171,7 @@
 
   if (should_enable) {
     tablet_mode_window_manager_.reset(new TabletModeWindowManager());
-    Shell::Get()->metrics()->RecordUserMetricsAction(UMA_MAXIMIZE_MODE_ENABLED);
+    base::RecordAction(base::UserMetricsAction("Touchview_Enabled"));
     RecordTabletModeUsageInterval(TABLET_MODE_INTERVAL_INACTIVE);
     for (auto& observer : tablet_mode_observers_)
       observer.OnTabletModeStarted();
@@ -186,8 +185,7 @@
     for (auto& observer : tablet_mode_observers_)
       observer.OnTabletModeEnding();
     tablet_mode_window_manager_.reset();
-    Shell::Get()->metrics()->RecordUserMetricsAction(
-        UMA_MAXIMIZE_MODE_DISABLED);
+    base::RecordAction(base::UserMetricsAction("Touchview_Disabled"));
     RecordTabletModeUsageInterval(TABLET_MODE_INTERVAL_ACTIVE);
     for (auto& observer : tablet_mode_observers_)
       observer.OnTabletModeEnded();
diff --git a/ash/wm/window_cycle_controller.cc b/ash/wm/window_cycle_controller.cc
index d119db3..bbea023f 100644
--- a/ash/wm/window_cycle_controller.cc
+++ b/ash/wm/window_cycle_controller.cc
@@ -8,6 +8,7 @@
 #include "ash/metrics/task_switch_source.h"
 #include "ash/metrics/user_metrics_recorder.h"
 #include "ash/public/cpp/shell_window_ids.h"
+#include "ash/public/cpp/window_properties.h"
 #include "ash/session/session_controller.h"
 #include "ash/shell.h"
 #include "ash/shell_port.h"
@@ -73,7 +74,8 @@
     return !state->IsUserPositionable() || state->is_dragged() ||
            window->GetRootWindow()
                ->GetChildById(kShellWindowId_AppListContainer)
-               ->Contains(window);
+               ->Contains(window) ||
+           !window->GetProperty(kShowInOverviewKey);
   };
   window_list.erase(std::remove_if(window_list.begin(), window_list.end(),
                                    window_is_ineligible),
diff --git a/ash/wm/window_cycle_controller_unittest.cc b/ash/wm/window_cycle_controller_unittest.cc
index 9c83f4d..268c7ad9 100644
--- a/ash/wm/window_cycle_controller_unittest.cc
+++ b/ash/wm/window_cycle_controller_unittest.cc
@@ -11,6 +11,7 @@
 #include "ash/focus_cycler.h"
 #include "ash/public/cpp/config.h"
 #include "ash/public/cpp/shell_window_ids.h"
+#include "ash/public/cpp/window_properties.h"
 #include "ash/scoped_root_window_for_new_windows.h"
 #include "ash/session/session_controller.h"
 #include "ash/session/test_session_controller_client.h"
@@ -256,6 +257,20 @@
   EXPECT_FALSE(wm::IsActiveWindow(window0.get()));
   EXPECT_FALSE(wm::IsActiveWindow(window1.get()));
   EXPECT_FALSE(wm::IsActiveWindow(window2.get()));
+
+  modal_window.reset();
+  std::unique_ptr<Window> skip_overview_window(
+      CreateTestWindowInShellWithId(-3));
+  skip_overview_window->SetProperty(kShowInOverviewKey, false);
+  wm::ActivateWindow(window0.get());
+  wm::ActivateWindow(skip_overview_window.get());
+  wm::ActivateWindow(window1.get());
+  EXPECT_FALSE(wm::IsActiveWindow(window0.get()));
+  controller->HandleCycleWindow(WindowCycleController::FORWARD);
+  controller->CompleteCycling();
+  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
+  EXPECT_FALSE(wm::IsActiveWindow(skip_overview_window.get()));
+  EXPECT_FALSE(wm::IsActiveWindow(window1.get()));
 }
 
 // Cycles between a maximized and normal window.
diff --git a/ash/wm/workspace/workspace_event_handler.cc b/ash/wm/workspace/workspace_event_handler.cc
index ebbbc037..e945c1fd3 100644
--- a/ash/wm/workspace/workspace_event_handler.cc
+++ b/ash/wm/workspace/workspace_event_handler.cc
@@ -4,12 +4,11 @@
 
 #include "ash/wm/workspace/workspace_event_handler.h"
 
-#include "ash/metrics/user_metrics_recorder.h"
-#include "ash/shell.h"
 #include "ash/touch/touch_uma.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
 #include "ash/wm/wm_event.h"
+#include "base/metrics/user_metrics.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_delegate.h"
 #include "ui/base/hit_test.h"
@@ -51,8 +50,8 @@
         if (event->flags() & ui::EF_IS_DOUBLE_CLICK) {
           int component = wm::GetNonClientComponent(target, event->location());
           if (component == HTCAPTION && component == click_component_) {
-            Shell::Get()->metrics()->RecordUserMetricsAction(
-                UMA_TOGGLE_MAXIMIZE_CAPTION_CLICK);
+            base::RecordAction(
+                base::UserMetricsAction("Caption_ClickTogglesMaximize"));
             const wm::WMEvent wm_event(wm::WM_EVENT_TOGGLE_MAXIMIZE_CAPTION);
             target_state->OnWMEvent(&wm_event);
             event->StopPropagation();
@@ -88,8 +87,8 @@
   }
 
   if (click_component_ == previous_target_component) {
-    Shell::Get()->metrics()->RecordUserMetricsAction(
-        UMA_TOGGLE_MAXIMIZE_CAPTION_GESTURE);
+    base::RecordAction(
+        base::UserMetricsAction("Caption_GestureTogglesMaximize"));
     TouchUMA::GetInstance()->RecordGestureAction(GESTURE_MAXIMIZE_DOUBLETAP);
     const wm::WMEvent wm_event(wm::WM_EVENT_TOGGLE_MAXIMIZE_CAPTION);
     wm::GetWindowState(target)->OnWMEvent(&wm_event);
@@ -105,14 +104,14 @@
   if ((event->flags() & ui::EF_IS_DOUBLE_CLICK) != 0 && target->delegate()) {
     const int component = wm::GetNonClientComponent(target, event->location());
     if (component == HTBOTTOM || component == HTTOP) {
-      Shell::Get()->metrics()->RecordUserMetricsAction(
-          UMA_TOGGLE_SINGLE_AXIS_MAXIMIZE_BORDER_CLICK);
+      base::RecordAction(base::UserMetricsAction(
+          "WindowBorder_ClickTogglesSingleAxisMaximize"));
       const wm::WMEvent wm_event(wm::WM_EVENT_TOGGLE_VERTICAL_MAXIMIZE);
       target_state->OnWMEvent(&wm_event);
       event->StopPropagation();
     } else if (component == HTLEFT || component == HTRIGHT) {
-      Shell::Get()->metrics()->RecordUserMetricsAction(
-          UMA_TOGGLE_SINGLE_AXIS_MAXIMIZE_BORDER_CLICK);
+      base::RecordAction(base::UserMetricsAction(
+          "WindowBorder_ClickTogglesSingleAxisMaximize"));
       const wm::WMEvent wm_event(wm::WM_EVENT_TOGGLE_HORIZONTAL_MAXIMIZE);
       target_state->OnWMEvent(&wm_event);
       event->StopPropagation();
diff --git a/ash/wm/workspace/workspace_window_resizer.cc b/ash/wm/workspace/workspace_window_resizer.cc
index 3d34a90..474a1f0 100644
--- a/ash/wm/workspace/workspace_window_resizer.cc
+++ b/ash/wm/workspace/workspace_window_resizer.cc
@@ -9,8 +9,6 @@
 #include <utility>
 #include <vector>
 
-#include "ash/metrics/user_metrics_action.h"
-#include "ash/metrics/user_metrics_recorder.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/root_window_controller.h"
 #include "ash/screen_util.h"
@@ -25,6 +23,7 @@
 #include "ash/wm/workspace/two_step_edge_cycler.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/weak_ptr.h"
+#include "base/metrics/user_metrics.h"
 #include "ui/aura/client/window_types.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_delegate.h"
@@ -409,9 +408,10 @@
     const wm::WMEvent event(snap_type_ == SNAP_LEFT ? wm::WM_EVENT_SNAP_LEFT
                                                     : wm::WM_EVENT_SNAP_RIGHT);
     window_state()->OnWMEvent(&event);
-    Shell::Get()->metrics()->RecordUserMetricsAction(
-        snap_type_ == SNAP_LEFT ? UMA_DRAG_MAXIMIZE_LEFT
-                                : UMA_DRAG_MAXIMIZE_RIGHT);
+    if (snap_type_ == SNAP_LEFT)
+      base::RecordAction(base::UserMetricsAction("WindowDrag_MaximizeLeft"));
+    else
+      base::RecordAction(base::UserMetricsAction("WindowDrag_MaximizeRight"));
     snapped = true;
   }
 
diff --git a/base/android/jni_generator/SampleForTests_jni.golden b/base/android/jni_generator/SampleForTests_jni.golden
index 5754e7e..db497a3c 100644
--- a/base/android/jni_generator/SampleForTests_jni.golden
+++ b/base/android/jni_generator/SampleForTests_jni.golden
@@ -474,14 +474,6 @@
   return base::android::ScopedJavaLocalRef<jstring>(env, ret);
 }
 
-// Step 3: RegisterNatives.
-
-// TODO(agrieve): Remove these empty registration functions and functions
-// calling them. https://crbug.com/683256.
-inline bool RegisterNativesImpl(JNIEnv* env) {
-  return true;
-}
-
 }  // namespace android
 }  // namespace base
 
diff --git a/base/android/jni_generator/jni_generator.py b/base/android/jni_generator/jni_generator.py
index afe6e0c..c7cee4b 100755
--- a/base/android/jni_generator/jni_generator.py
+++ b/base/android/jni_generator/jni_generator.py
@@ -900,8 +900,6 @@
 // Step 2: method stubs.
 $METHOD_STUBS
 
-// Step 3: RegisterNatives.
-$REGISTER_NATIVES_EMPTY
 $CLOSE_NAMESPACE
 
 #endif  // ${HEADER_GUARD}
@@ -913,7 +911,6 @@
         'CONSTANT_FIELDS': self.GetConstantFieldsString(),
         'METHOD_STUBS': self.GetMethodStubsString(),
         'OPEN_NAMESPACE': self.GetOpenNamespaceString(),
-        'REGISTER_NATIVES_EMPTY': self.GetOriginalRegisterNativesString(),
         'CLOSE_NAMESPACE': self.GetCloseNamespaceString(),
         'HEADER_GUARD': self.header_guard,
         'INCLUDES': self.GetIncludesString(),
@@ -952,21 +949,6 @@
     includes = self.options.includes.split(',')
     return '\n'.join('#include "%s"' % x for x in includes)
 
-  # TODO(agrieve): Remove this function when deleting original registers.
-  # https://crbug.com/683256.
-  def GetOriginalRegisterNativesString(self):
-    """Return the code for original RegisterNatives"""
-    if len(self.natives) == 0:
-      return ''
-
-    return """
-// TODO(agrieve): Remove these empty registration functions and functions
-// calling them. https://crbug.com/683256.
-inline bool RegisterNativesImpl(JNIEnv* env) {
-  return true;
-}
-"""
-
   def GetOpenNamespaceString(self):
     if self.namespace:
       all_namespaces = ['namespace %s {' % ns
diff --git a/base/android/jni_generator/testCalledByNatives.golden b/base/android/jni_generator/testCalledByNatives.golden
index 314614d..420844e7 100644
--- a/base/android/jni_generator/testCalledByNatives.golden
+++ b/base/android/jni_generator/testCalledByNatives.golden
@@ -514,6 +514,4 @@
   return base::android::ScopedJavaLocalRef<jobject>(env, ret);
 }
 
-// Step 3: RegisterNatives.
-
 #endif  // org_chromium_TestJni_JNI
diff --git a/base/android/jni_generator/testConstantsFromJavaP.golden b/base/android/jni_generator/testConstantsFromJavaP.golden
index d511200..769a7eb 100644
--- a/base/android/jni_generator/testConstantsFromJavaP.golden
+++ b/base/android/jni_generator/testConstantsFromJavaP.golden
@@ -2223,8 +2223,6 @@
   jni_generator::CheckException(env);
 }
 
-// Step 3: RegisterNatives.
-
 }  // namespace JNI_MotionEvent
 
 #endif  // android_view_MotionEvent_JNI
diff --git a/base/android/jni_generator/testFromJavaP.golden b/base/android/jni_generator/testFromJavaP.golden
index 85d81852..73ed4b3 100644
--- a/base/android/jni_generator/testFromJavaP.golden
+++ b/base/android/jni_generator/testFromJavaP.golden
@@ -258,8 +258,6 @@
   return base::android::ScopedJavaLocalRef<jobject>(env, ret);
 }
 
-// Step 3: RegisterNatives.
-
 }  // namespace JNI_InputStream
 
 #endif  // java_io_InputStream_JNI
diff --git a/base/android/jni_generator/testFromJavaPGenerics.golden b/base/android/jni_generator/testFromJavaPGenerics.golden
index f0c19b3..164db66 100644
--- a/base/android/jni_generator/testFromJavaPGenerics.golden
+++ b/base/android/jni_generator/testFromJavaPGenerics.golden
@@ -54,8 +54,6 @@
   jni_generator::CheckException(env);
 }
 
-// Step 3: RegisterNatives.
-
 }  // namespace JNI_HashSet
 
 #endif  // java_util_HashSet_JNI
diff --git a/base/android/jni_generator/testInnerClassNatives.golden b/base/android/jni_generator/testInnerClassNatives.golden
index 3e44f78..93316ad 100644
--- a/base/android/jni_generator/testInnerClassNatives.golden
+++ b/base/android/jni_generator/testInnerClassNatives.golden
@@ -59,12 +59,4 @@
   return Init(env, base::android::JavaParamRef<jobject>(env, jcaller));
 }
 
-// Step 3: RegisterNatives.
-
-// TODO(agrieve): Remove these empty registration functions and functions
-// calling them. https://crbug.com/683256.
-inline bool RegisterNativesImpl(JNIEnv* env) {
-  return true;
-}
-
 #endif  // org_chromium_TestJni_JNI
diff --git a/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden b/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden
index cc9d3cf..d9712089 100644
--- a/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden
+++ b/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden
@@ -67,12 +67,4 @@
   return Init(env, base::android::JavaParamRef<jobject>(env, jcaller));
 }
 
-// Step 3: RegisterNatives.
-
-// TODO(agrieve): Remove these empty registration functions and functions
-// calling them. https://crbug.com/683256.
-inline bool RegisterNativesImpl(JNIEnv* env) {
-  return true;
-}
-
 #endif  // org_chromium_TestJni_JNI
diff --git a/base/android/jni_generator/testInnerClassNativesMultiple.golden b/base/android/jni_generator/testInnerClassNativesMultiple.golden
index bc431b3..ae93a86 100644
--- a/base/android/jni_generator/testInnerClassNativesMultiple.golden
+++ b/base/android/jni_generator/testInnerClassNativesMultiple.golden
@@ -85,12 +85,4 @@
   return Init(env, base::android::JavaParamRef<jobject>(env, jcaller));
 }
 
-// Step 3: RegisterNatives.
-
-// TODO(agrieve): Remove these empty registration functions and functions
-// calling them. https://crbug.com/683256.
-inline bool RegisterNativesImpl(JNIEnv* env) {
-  return true;
-}
-
 #endif  // org_chromium_TestJni_JNI
diff --git a/base/android/jni_generator/testMultipleJNIAdditionalImport.golden b/base/android/jni_generator/testMultipleJNIAdditionalImport.golden
index c29e542c..4a3d91c2 100644
--- a/base/android/jni_generator/testMultipleJNIAdditionalImport.golden
+++ b/base/android/jni_generator/testMultipleJNIAdditionalImport.golden
@@ -70,12 +70,4 @@
   jni_generator::CheckException(env);
 }
 
-// Step 3: RegisterNatives.
-
-// TODO(agrieve): Remove these empty registration functions and functions
-// calling them. https://crbug.com/683256.
-inline bool RegisterNativesImpl(JNIEnv* env) {
-  return true;
-}
-
 #endif  // org_chromium_foo_Foo_JNI
diff --git a/base/android/jni_generator/testNativeExportsOnlyOption.golden b/base/android/jni_generator/testNativeExportsOnlyOption.golden
index d4d7569..f5be7c4 100644
--- a/base/android/jni_generator/testNativeExportsOnlyOption.golden
+++ b/base/android/jni_generator/testNativeExportsOnlyOption.golden
@@ -242,12 +242,4 @@
   return base::android::ScopedJavaLocalRef<jstring>(env, ret);
 }
 
-// Step 3: RegisterNatives.
-
-// TODO(agrieve): Remove these empty registration functions and functions
-// calling them. https://crbug.com/683256.
-inline bool RegisterNativesImpl(JNIEnv* env) {
-  return true;
-}
-
 #endif  // org_chromium_example_jni_generator_SampleForTests_JNI
diff --git a/base/android/jni_generator/testNatives.golden b/base/android/jni_generator/testNatives.golden
index 89322b1..b57f935 100644
--- a/base/android/jni_generator/testNatives.golden
+++ b/base/android/jni_generator/testNatives.golden
@@ -219,12 +219,4 @@
       jcaller), base::android::JavaParamRef<jthrowable>(env, e)).Release();
 }
 
-// Step 3: RegisterNatives.
-
-// TODO(agrieve): Remove these empty registration functions and functions
-// calling them. https://crbug.com/683256.
-inline bool RegisterNativesImpl(JNIEnv* env) {
-  return true;
-}
-
 #endif  // org_chromium_TestJni_JNI
diff --git a/base/android/jni_generator/testNativesLong.golden b/base/android/jni_generator/testNativesLong.golden
index 1bbeacd4..18d58fa4 100644
--- a/base/android/jni_generator/testNativesLong.golden
+++ b/base/android/jni_generator/testNativesLong.golden
@@ -42,12 +42,4 @@
       jcaller));
 }
 
-// Step 3: RegisterNatives.
-
-// TODO(agrieve): Remove these empty registration functions and functions
-// calling them. https://crbug.com/683256.
-inline bool RegisterNativesImpl(JNIEnv* env) {
-  return true;
-}
-
 #endif  // org_chromium_TestJni_JNI
diff --git a/base/android/jni_generator/testSingleJNIAdditionalImport.golden b/base/android/jni_generator/testSingleJNIAdditionalImport.golden
index 75295ba3..c8b6907 100644
--- a/base/android/jni_generator/testSingleJNIAdditionalImport.golden
+++ b/base/android/jni_generator/testSingleJNIAdditionalImport.golden
@@ -65,12 +65,4 @@
   jni_generator::CheckException(env);
 }
 
-// Step 3: RegisterNatives.
-
-// TODO(agrieve): Remove these empty registration functions and functions
-// calling them. https://crbug.com/683256.
-inline bool RegisterNativesImpl(JNIEnv* env) {
-  return true;
-}
-
 #endif  // org_chromium_foo_Foo_JNI
diff --git a/base/debug/stack_trace_posix.cc b/base/debug/stack_trace_posix.cc
index db32e5b..597c81d 100644
--- a/base/debug/stack_trace_posix.cc
+++ b/base/debug/stack_trace_posix.cc
@@ -520,7 +520,7 @@
         if (strcmp((it->first).c_str(), file_path) == 0) {
           // POSIX.1-2004 requires an implementation to guarantee that dup()
           // is async-signal-safe.
-          fd = dup(it->second);
+          fd = HANDLE_EINTR(dup(it->second));
           break;
         }
       }
diff --git a/base/feature_list.cc b/base/feature_list.cc
index ce4503bf..e071089 100644
--- a/base/feature_list.cc
+++ b/base/feature_list.cc
@@ -282,9 +282,7 @@
   // DCHECK is also forced to be FATAL if we are running a death-test.
   // TODO(asvitkine): If we find other use-cases that need integrating here
   // then define a proper API/hook for the purpose.
-  constexpr base::Feature kDCheckIsFatalFeature{
-      "DcheckIsFatal", base::FEATURE_DISABLED_BY_DEFAULT};
-  if (base::FeatureList::IsEnabled(kDCheckIsFatalFeature) ||
+  if (base::FeatureList::IsEnabled(kSyzyAsanDCheckIsFatalFeature) ||
       base::CommandLine::ForCurrentProcess()->HasSwitch(
           "gtest_internal_run_death_test")) {
     logging::LOG_DCHECK = logging::LOG_FATAL;
diff --git a/base/feature_list.h b/base/feature_list.h
index 856e84cb..42bc01d 100644
--- a/base/feature_list.h
+++ b/base/feature_list.h
@@ -43,6 +43,14 @@
   const FeatureState default_state;
 };
 
+#if DCHECK_IS_ON() && defined(SYZYASAN)
+// SyzyASAN builds have DCHECKs built-in, but configurable at run-time to been
+// fatal, or not, via a DcheckIsFatal feature. We define the Feature here since
+// it is checked in FeatureList::SetInstance(). See crbug.com/596231.
+constexpr Feature kSyzyAsanDCheckIsFatalFeature{
+    "DcheckIsFatal", base::FEATURE_DISABLED_BY_DEFAULT};
+#endif  // defined(SYZYASAN)
+
 // The FeatureList class is used to determine whether a given feature is on or
 // off. It provides an authoritative answer, taking into account command-line
 // overrides and experimental control.
diff --git a/base/files/file_posix.cc b/base/files/file_posix.cc
index dc127e5..3c2346e4 100644
--- a/base/files/file_posix.cc
+++ b/base/files/file_posix.cc
@@ -381,7 +381,7 @@
 
   SCOPED_FILE_TRACE("Duplicate");
 
-  PlatformFile other_fd = dup(GetPlatformFile());
+  PlatformFile other_fd = HANDLE_EINTR(dup(GetPlatformFile()));
   if (other_fd == -1)
     return File(OSErrorToFileError(errno));
 
diff --git a/base/process/launch_fuchsia.cc b/base/process/launch_fuchsia.cc
index 6c3b9d8..3f37088 100644
--- a/base/process/launch_fuchsia.cc
+++ b/base/process/launch_fuchsia.cc
@@ -17,59 +17,40 @@
 
 namespace {
 
-// TODO(758683): Replace this with a call to LaunchProcess().
-bool GetAppOutputInternal(const std::vector<std::string>& argv,
+bool GetAppOutputInternal(const CommandLine& cmd_line,
                           bool include_stderr,
                           std::string* output,
                           int* exit_code) {
   DCHECK(exit_code);
 
-  std::vector<const char*> argv_cstr;
-  argv_cstr.reserve(argv.size() + 1);
-  for (const auto& arg : argv)
-    argv_cstr.push_back(arg.c_str());
-  argv_cstr.push_back(nullptr);
+  LaunchOptions options;
 
-  launchpad_t* lp = nullptr;
-  launchpad_create(GetDefaultJob(), argv_cstr[0], &lp);
-  launchpad_load_from_file(lp, argv_cstr[0]);
-  launchpad_set_args(lp, argv.size(), argv_cstr.data());
-  launchpad_clone(lp, LP_CLONE_MXIO_NAMESPACE | LP_CLONE_MXIO_CWD |
-                          LP_CLONE_DEFAULT_JOB | LP_CLONE_ENVIRON);
-  launchpad_clone_fd(lp, STDIN_FILENO, STDIN_FILENO);
-  int pipe_fd;
-  mx_status_t status = launchpad_add_pipe(lp, &pipe_fd, STDOUT_FILENO);
-  if (status != MX_OK) {
-    LOG(ERROR) << "launchpad_add_pipe failed: " << mx_status_get_string(status);
-    launchpad_destroy(lp);
+  // LaunchProcess will automatically clone any stdio fd we do not explicitly
+  // map.
+  int pipe_fd[2];
+  if (pipe(pipe_fd) < 0)
     return false;
-  }
-
+  options.fds_to_remap.emplace_back(pipe_fd[1], STDOUT_FILENO);
   if (include_stderr)
-    launchpad_clone_fd(lp, pipe_fd, STDERR_FILENO);
-  else
-    launchpad_clone_fd(lp, STDERR_FILENO, STDERR_FILENO);
+    options.fds_to_remap.emplace_back(pipe_fd[1], STDERR_FILENO);
 
-  mx_handle_t proc;
-  const char* errmsg;
-  status = launchpad_go(lp, &proc, &errmsg);
-  if (status != MX_OK) {
-    LOG(ERROR) << "launchpad_go failed: " << errmsg
-               << ", status=" << mx_status_get_string(status);
+  Process process = LaunchProcess(cmd_line, options);
+  close(pipe_fd[1]);
+  if (!process.IsValid()) {
+    close(pipe_fd[0]);
     return false;
   }
 
   output->clear();
   for (;;) {
     char buffer[256];
-    ssize_t bytes_read = read(pipe_fd, buffer, sizeof(buffer));
+    ssize_t bytes_read = read(pipe_fd[0], buffer, sizeof(buffer));
     if (bytes_read <= 0)
       break;
     output->append(buffer, bytes_read);
   }
-  close(pipe_fd);
+  close(pipe_fd[0]);
 
-  Process process(proc);
   return process.WaitForExit(exit_code);
 }
 
@@ -173,24 +154,24 @@
 }
 
 bool GetAppOutput(const CommandLine& cl, std::string* output) {
-  return GetAppOutput(cl.argv(), output);
-}
-
-bool GetAppOutput(const std::vector<std::string>& argv, std::string* output) {
   int exit_code;
-  bool result = GetAppOutputInternal(argv, false, output, &exit_code);
+  bool result = GetAppOutputInternal(cl, false, output, &exit_code);
   return result && exit_code == EXIT_SUCCESS;
 }
 
+bool GetAppOutput(const std::vector<std::string>& argv, std::string* output) {
+  return GetAppOutput(CommandLine(argv), output);
+}
+
 bool GetAppOutputAndError(const CommandLine& cl, std::string* output) {
-  return GetAppOutputAndError(cl.argv(), output);
+  int exit_code;
+  bool result = GetAppOutputInternal(cl, true, output, &exit_code);
+  return result && exit_code == EXIT_SUCCESS;
 }
 
 bool GetAppOutputAndError(const std::vector<std::string>& argv,
                           std::string* output) {
-  int exit_code;
-  bool result = GetAppOutputInternal(argv, true, output, &exit_code);
-  return result && exit_code == EXIT_SUCCESS;
+  return GetAppOutputAndError(CommandLine(argv), output);
 }
 
 bool GetAppOutputWithExitCode(const CommandLine& cl,
@@ -199,7 +180,7 @@
   // Contrary to GetAppOutput(), |true| return here means that the process was
   // launched and the exit code was waited upon successfully, but not
   // necessarily that the exit code was EXIT_SUCCESS.
-  return GetAppOutputInternal(cl.argv(), false, output, exit_code);
+  return GetAppOutputInternal(cl, false, output, exit_code);
 }
 
 }  // namespace base
diff --git a/base/process/process_util_unittest.cc b/base/process/process_util_unittest.cc
index 24ae0ebb..366ec4c2 100644
--- a/base/process/process_util_unittest.cc
+++ b/base/process/process_util_unittest.cc
@@ -698,7 +698,7 @@
   int pipe_fds[2];
   int result = pipe(pipe_fds);
   ASSERT_EQ(0, result);
-  int backup_stdio = dup(STDOUT_FILENO);
+  int backup_stdio = HANDLE_EINTR(dup(STDOUT_FILENO));
   ASSERT_LE(0, backup_stdio);
   result = dup2(pipe_fds[1], STDOUT_FILENO);
   ASSERT_EQ(STDOUT_FILENO, result);
diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc
index 42d39e0..2e409c6 100644
--- a/base/trace_event/memory_dump_manager.cc
+++ b/base/trace_event/memory_dump_manager.cc
@@ -471,14 +471,6 @@
 void MemoryDumpManager::CreateProcessDump(
     const MemoryDumpRequestArgs& args,
     const ProcessMemoryDumpCallback& callback) {
-  if (!is_initialized()) {
-    VLOG(1) << "CreateProcessDump() FAIL: MemoryDumpManager is not initialized";
-    if (!callback.is_null()) {
-      callback.Run(false /* success */, args.dump_guid, nullptr);
-    }
-    return;
-  }
-
   char guid_str[20];
   sprintf(guid_str, "0x%" PRIx64, args.dump_guid);
   TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(kTraceCategory, "ProcessMemoryDump",
@@ -695,7 +687,7 @@
 
   if (!pmd_async_state->callback.is_null()) {
     pmd_async_state->callback.Run(
-        pmd_async_state->dump_successful, dump_guid,
+        true /* success */, dump_guid,
         std::move(pmd_async_state->process_memory_dump));
     pmd_async_state->callback.Reset();
   }
@@ -813,7 +805,6 @@
       heap_profiler_serialization_state(
           std::move(heap_profiler_serialization_state_in)),
       callback(callback),
-      dump_successful(true),
       callback_task_runner(ThreadTaskRunnerHandle::Get()),
       dump_thread_task_runner(std::move(dump_thread_task_runner)) {
   pending_dump_providers.reserve(dump_providers.size());
diff --git a/base/trace_event/memory_dump_manager.h b/base/trace_event/memory_dump_manager.h
index 02d37c13..72e61ad 100644
--- a/base/trace_event/memory_dump_manager.h
+++ b/base/trace_event/memory_dump_manager.h
@@ -216,9 +216,6 @@
     // Callback passed to the initial call to CreateProcessDump().
     ProcessMemoryDumpCallback callback;
 
-    // The |success| field that will be passed as argument to the |callback|.
-    bool dump_successful;
-
     // The thread on which FinalizeDumpAndAddToTrace() (and hence |callback|)
     // should be invoked. This is the thread on which the initial
     // CreateProcessDump() request was called.
diff --git a/base/trace_event/trace_config_memory_test_util.h b/base/trace_event/trace_config_memory_test_util.h
index 744e8a8..57608fd6 100644
--- a/base/trace_event/trace_config_memory_test_util.h
+++ b/base/trace_event/trace_config_memory_test_util.h
@@ -19,6 +19,9 @@
         "{"
         "\"enable_argument_filter\":false,"
         "\"enable_systrace\":false,"
+        "\"excluded_categories\":["
+        "\"*\""
+        "],"
         "\"included_categories\":["
         "\"%s\""
         "],"
@@ -50,6 +53,9 @@
         "{"
         "\"enable_argument_filter\":false,"
         "\"enable_systrace\":false,"
+        "\"excluded_categories\":["
+        "\"*\""
+        "],"
         "\"included_categories\":["
         "\"%s\""
         "],"
@@ -81,6 +87,9 @@
         "{"
         "\"enable_argument_filter\":false,"
         "\"enable_systrace\":false,"
+        "\"excluded_categories\":["
+        "\"*\""
+        "],"
         "\"included_categories\":["
         "\"%s\""
         "],"
@@ -99,6 +108,9 @@
         "{"
         "\"enable_argument_filter\":false,"
         "\"enable_systrace\":false,"
+        "\"excluded_categories\":["
+        "\"*\""
+        "],"
         "\"included_categories\":["
         "\"%s\""
         "],"
@@ -112,6 +124,9 @@
         "{"
         "\"enable_argument_filter\":false,"
         "\"enable_systrace\":false,"
+        "\"excluded_categories\":["
+        "\"*\""
+        "],"
         "\"included_categories\":["
         "\"%s\""
         "],"
@@ -135,6 +150,9 @@
         "{"
         "\"enable_argument_filter\":false,"
         "\"enable_systrace\":false,"
+        "\"excluded_categories\":["
+        "\"*\""
+        "],"
         "\"included_categories\":["
         "\"%s\""
         "],"
diff --git a/build/android/apk_operations.py b/build/android/apk_operations.py
index 09b097b9..ee5979c0 100755
--- a/build/android/apk_operations.py
+++ b/build/android/apk_operations.py
@@ -9,8 +9,10 @@
 import os
 import pipes
 import posixpath
+import random
 import re
 import shlex
+import subprocess
 import sys
 
 import devil_chromium
@@ -352,6 +354,57 @@
     print 'Total: %skb (%.1fmb)' % (total, total / 1024.0)
 
 
+def _RunLogcat(device, package_name, verbose):
+  def get_my_pids():
+    my_pids = []
+    for pids in device.GetPids(package_name).values():
+      my_pids.extend(pids)
+    return [int(pid) for pid in my_pids]
+
+  def process_line(line, fast=False):
+    if verbose:
+      if not fast:
+        sys.stdout.write(line)
+    else:
+      if line.startswith('------'):
+        return
+      tokens = line.split(None, 4)
+      pid = int(tokens[2])
+      priority = tokens[4]
+      if pid in my_pids or (not fast and priority == 'F'):
+        sys.stdout.write(line)
+      elif pid in not_my_pids:
+        return
+      elif fast:
+        # Skip checking whether our package spawned new processes.
+        not_my_pids.add(pid)
+      else:
+        # Check and add the pid if it is a new one from our package.
+        my_pids.update(get_my_pids())
+        if pid in my_pids:
+          sys.stdout.write(line)
+        else:
+          not_my_pids.add(pid)
+
+  adb_path = adb_wrapper.AdbWrapper.GetAdbPath()
+  cmd = [adb_path, '-s', device.serial, 'logcat', '-v', 'threadtime']
+  process = subprocess.Popen(cmd, stdout=subprocess.PIPE, bufsize=1)
+  my_pids = set(get_my_pids())
+  not_my_pids = set()
+
+  nonce = 'apk_wrappers.py nonce={}'.format(random.random())
+  device.RunShellCommand(['log', nonce])
+  fast = True
+  try:
+    while True:
+      line = process.stdout.readline()
+      process_line(line, fast)
+      if fast and nonce in line:
+        fast = False
+  except KeyboardInterrupt:
+    process.terminate()
+
+
 def _RunPs(devices, package_name):
   parallel_devices = device_utils.DeviceUtils.parallel(devices)
   all_pids = parallel_devices.GetPids(package_name).pGet(None)
@@ -590,7 +643,7 @@
                              self.install_dict['apk_path']))
         if not self.apk_helper and args.apk_path:
           self.apk_helper = apk_helper.ToHelper(args.apk_path)
-        else:
+        if not self.apk_helper:
           self._parser.error(
               'Neither incremental nor non-incremental apk is built.')
 
@@ -713,13 +766,13 @@
 
 class _LogcatCommand(_Command):
   name = 'logcat'
-  description = 'Runs "adb logcat"'
+  description = 'Runs "adb logcat" filtering to just the current APK processes'
+  needs_package_name = True
   calls_exec = True
 
   def Run(self):
-    adb_path = adb_wrapper.AdbWrapper.GetAdbPath()
-    cmd = [adb_path, '-s', self.devices[0].serial, 'logcat']
-    os.execv(adb_path, cmd)
+    _RunLogcat(self.devices[0], self.args.package_name,
+               bool(self.args.verbose_count))
 
 
 class _PsCommand(_Command):
diff --git a/build/android/gyp/aar.py b/build/android/gyp/aar.py
index 6c0bc89..e8196e5a 100755
--- a/build/android/gyp/aar.py
+++ b/build/android/gyp/aar.py
@@ -38,76 +38,97 @@
   return True
 
 
+def _CreateInfo(aar_file):
+  data = {}
+  data['aidl'] = []
+  data['assets'] = []
+  data['resources'] = []
+  data['subjars'] = []
+  data['subjar_tuples'] = []
+  data['has_classes_jar'] = False
+  data['has_proguard_flags'] = False
+  data['has_native_libraries'] = False
+  data['has_r_text_file'] = False
+  with zipfile.ZipFile(aar_file) as z:
+    data['is_manifest_empty'] = (
+        _IsManifestEmpty(z.read('AndroidManifest.xml')))
+
+    for name in z.namelist():
+      if name.endswith('/'):
+        continue
+      if name.startswith('aidl/'):
+        data['aidl'].append(name)
+      elif name.startswith('res/'):
+        data['resources'].append(name)
+      elif name.startswith('libs/') and name.endswith('.jar'):
+        label = posixpath.basename(name)[:-4]
+        label = re.sub(r'[^a-zA-Z0-9._]', '_', label)
+        data['subjars'].append(name)
+        data['subjar_tuples'].append([label, name])
+      elif name.startswith('assets/'):
+        data['assets'].append(name)
+      elif name.startswith('jni/'):
+        data['has_native_libraries'] = True
+      elif name == 'classes.jar':
+        data['has_classes_jar'] = True
+      elif name == 'proguard.txt':
+        data['has_proguard_flags'] = True
+      elif name == 'R.txt':
+        # Some AARs, e.g. gvr_controller_java, have empty R.txt. Such AARs
+        # have no resources as well. We treat empty R.txt as having no R.txt.
+        data['has_r_text_file'] = (z.read('R.txt').strip() != '')
+
+  return """\
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+""" + gn_helpers.ToGNString(data)
+
+
+def _AddCommonArgs(parser):
+  parser.add_argument('aar_file',
+                      help='Path to the AAR file.',
+                      type=os.path.normpath)
+
+
 def main():
   parser = argparse.ArgumentParser(description=__doc__)
-  parser.add_argument('--input-file',
-                      help='Path to the AAR file.',
-                      required=True,
-                      metavar='FILE')
-  parser.add_argument('--extract',
-                      help='Extract the files to output directory.',
-                      action='store_true')
-  parser.add_argument('--list',
-                      help='List all the resource and jar files.',
-                      action='store_true')
-  parser.add_argument('--output-dir',
-                      help='Output directory for the extracted files. Must '
-                      'be set if --extract is set.',
-                      metavar='DIR')
+  command_parsers = parser.add_subparsers(dest='command')
+  subp = command_parsers.add_parser(
+      'list', help='Output a GN scope describing the contents of the .aar.')
+  _AddCommonArgs(subp)
+  subp.add_argument('--output',
+                    help='Output file.',
+                    type=argparse.FileType('w'),
+                    default='-')
+
+  subp = command_parsers.add_parser('extract', help='Extracts the .aar')
+  _AddCommonArgs(subp)
+  subp.add_argument('--output-dir',
+                    help='Output directory for the extracted files.',
+                    required=True,
+                    type=os.path.normpath)
+  subp.add_argument('--assert-info-file',
+                    help='Path to .info file. Asserts that it matches what '
+                         '"list" would output.',
+                    type=argparse.FileType('r'))
 
   args = parser.parse_args()
-  if not args.extract and not args.list:
-    parser.error('Either --extract or --list has to be specified.')
 
-  aar_file = args.input_file
-  output_dir = args.output_dir
-
-  if args.extract:
+  if args.command == 'extract':
+    if args.assert_info_file:
+      expected = _CreateInfo(args.aar_file)
+      actual = args.assert_info_file.read()
+      if actual != expected:
+        raise Exception('android_aar_prebuilt() cached .info file is '
+                        'out-of-date. Run gn gen with '
+                        'update_android_aar_prebuilts=true to update it.')
     # Clear previously extracted versions of the AAR.
-    shutil.rmtree(output_dir, True)
-    build_utils.ExtractAll(aar_file, path=output_dir)
+    shutil.rmtree(args.output_dir, True)
+    build_utils.ExtractAll(args.aar_file, path=args.output_dir)
 
-  if args.list:
-    data = {}
-    data['aidl'] = []
-    data['assets'] = []
-    data['resources'] = []
-    data['subjars'] = []
-    data['subjar_tuples'] = []
-    data['has_classes_jar'] = False
-    data['has_proguard_flags'] = False
-    data['has_native_libraries'] = False
-    data['has_r_text_file'] = False
-    with zipfile.ZipFile(aar_file) as z:
-      data['is_manifest_empty'] = (
-          _IsManifestEmpty(z.read('AndroidManifest.xml')))
-
-      for name in z.namelist():
-        if name.endswith('/'):
-          continue
-        if name.startswith('aidl/'):
-          data['aidl'].append(name)
-        elif name.startswith('res/'):
-          data['resources'].append(name)
-        elif name.startswith('libs/') and name.endswith('.jar'):
-          label = posixpath.basename(name)[:-4]
-          label = re.sub(r'[^a-zA-Z0-9._]', '_', label)
-          data['subjars'].append(name)
-          data['subjar_tuples'].append([label, name])
-        elif name.startswith('assets/'):
-          data['assets'].append(name)
-        elif name.startswith('jni/'):
-          data['has_native_libraries'] = True
-        elif name == 'classes.jar':
-          data['has_classes_jar'] = True
-        elif name == 'proguard.txt':
-          data['has_proguard_flags'] = True
-        elif name == 'R.txt':
-          # Some AARs, e.g. gvr_controller_java, have empty R.txt. Such AARs
-          # have no resources as well. We treat empty R.txt as having no R.txt.
-          data['has_r_text_file'] = (z.read('R.txt').strip() != '')
-
-    print gn_helpers.ToGNString(data)
+  elif args.command == 'list':
+    args.output.write(_CreateInfo(args.aar_file))
 
 
 if __name__ == '__main__':
diff --git a/build/android/pylib/local/local_test_server_spawner.py b/build/android/pylib/local/local_test_server_spawner.py
index 8e416fac..d114806 100644
--- a/build/android/pylib/local/local_test_server_spawner.py
+++ b/build/android/pylib/local/local_test_server_spawner.py
@@ -13,11 +13,6 @@
 with host_paths.SysPath(host_paths.BUILD_COMMON_PATH):
   import chrome_test_server_spawner
 
-
-# The tests should not need more than one test server instance.
-MAX_TEST_SERVER_INSTANCES = 1
-
-
 def _WaitUntil(predicate, max_attempts=5):
   """Blocks until the provided predicate (function) is true.
 
@@ -63,7 +58,7 @@
     super(LocalTestServerSpawner, self).__init__()
     self._device = device
     self._spawning_server = chrome_test_server_spawner.SpawningServer(
-        port, PortForwarderAndroid(device, tool), MAX_TEST_SERVER_INSTANCES)
+        port, PortForwarderAndroid(device, tool))
     self._tool = tool
 
   @property
diff --git a/build/check_gn_headers_whitelist.txt b/build/check_gn_headers_whitelist.txt
index e52c606..c052be5 100644
--- a/build/check_gn_headers_whitelist.txt
+++ b/build/check_gn_headers_whitelist.txt
@@ -57,7 +57,6 @@
 chrome/browser/media/webrtc/desktop_media_list_ash.h
 chrome/browser/media/webrtc/desktop_media_list_observer.h
 chrome/browser/media/webrtc/rtp_dump_type.h
-chrome/browser/media_galleries/fileapi/file_path_watcher_util.h
 chrome/browser/media_galleries/fileapi/iapps_data_provider.h
 chrome/browser/media_galleries/fileapi/itunes_data_provider.h
 chrome/browser/media_galleries/fileapi/picasa_data_provider.h
diff --git a/build/config/android/config.gni b/build/config/android/config.gni
index 6723744..d0091f0 100644
--- a/build/config/android/config.gni
+++ b/build/config/android/config.gni
@@ -75,6 +75,10 @@
     google_play_services_package = "//third_party/android_tools"
   }
 
+  if (!defined(android_support_library_package)) {
+    android_support_library_package = "//third_party/android_tools/support"
+  }
+
   if (!defined(system_webview_apk_target)) {
     system_webview_apk_target = "//android_webview:system_webview_apk"
   }
@@ -164,6 +168,10 @@
     # Ex. with this arg set to true, the chrome_public_apk target result in
     # chrome_public_apk_incremental being built.
     incremental_apk_by_default = false
+
+    # When true, updates all android_aar_prebuilt() .info files during gn gen.
+    # Refer to android_aar_prebuilt() for more details.
+    update_android_aar_prebuilts = false
   }
 
   # We need a second declare_args block to make sure we are using the overridden
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index 429bc32..f31f287 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -2934,22 +2934,33 @@
   # resources. For libraries without resources, it will not generate
   # corresponding android_resources targets.
   #
+  # To avoid slowing down "gn gen", an associated .info file must be committed
+  # along with the .aar file. In order to create this file, define the target
+  # and then run once with the gn arg "update_android_aar_prebuilts = true".
+  #
   # Variables
   #   aar_path: Path to the AAR.
+  #   info_path: Path to the .aar.info file (generated via
+  #       update_android_aar_prebuilts GN arg).
   #   proguard_configs: List of proguard configs to use in final apk step for
-  #     any apk that depends on this library.
+  #       any apk that depends on this library.
   #   ignore_aidl: Whether to ignore .aidl files found with the .aar.
   #   ignore_assets: Whether to ignore assets found in the .aar.
   #   ignore_native_libraries: Whether to ignore .so files found in the .aar.
   #   create_srcjar: If false, does not create an R.java file.
   #   TODO(jbudorick@): remove this arguments after crbug.com/522043 is fixed.
-  #   requires_android: Whether this target can only be used for compiling Android related targets.
+  #   requires_android: Whether this target can only be used for compiling
+  #       Android related targets.
   #
   # Example
   #   android_aar_prebuilt("foo_java") {
   #     aar_path = "foo.aar"
   #   }
   template("android_aar_prebuilt") {
+    _info_path = "$target_name.info"
+    if (defined(invoker.info_path)) {
+      _info_path = invoker.info_path
+    }
     _output_path = "${target_gen_dir}/${target_name}"
     _unpack_target_name = "${target_name}__unpack_aar"
     _ignore_aidl = defined(invoker.ignore_aidl) && invoker.ignore_aidl
@@ -2959,14 +2970,17 @@
 
     # Scan the AAR file and determine the resources and jar files.
     # Some libraries might not have resources; others might have two jars.
-    _scanned_files =
-        exec_script("//build/android/gyp/aar.py",
-                    [
-                      "--input-file",
-                      rebase_path(invoker.aar_path, root_build_dir),
-                      "--list",
-                    ],
-                    "scope")
+    if (update_android_aar_prebuilts) {
+      print("Writing " + rebase_path(_info_path, "//"))
+      exec_script("//build/android/gyp/aar.py",
+                  [
+                    "list",
+                    rebase_path(invoker.aar_path, root_build_dir),
+                    "--output",
+                    rebase_path(_info_path, root_build_dir),
+                  ])
+    }
+    _scanned_files = read_file(_info_path, "scope")
 
     assert(_ignore_aidl || _scanned_files.aidl == [],
            "android_aar_prebuilt() aidl not yet supported." +
@@ -2984,11 +2998,12 @@
     action(_unpack_target_name) {
       script = "//build/android/gyp/aar.py"  # Unzips the AAR
       args = [
-        "--input-file",
+        "extract",
         rebase_path(invoker.aar_path, root_build_dir),
         "--output-dir",
         rebase_path(_output_path, root_build_dir),
-        "--extract",
+        "--assert-info-file",
+        rebase_path(_info_path, root_build_dir),
       ]
       inputs = [
         invoker.aar_path,
@@ -3110,6 +3125,11 @@
     }
 
     java_group(target_name) {
+      forward_variables_from(invoker,
+                             [
+                               "testonly",
+                               "visibility",
+                             ])
       deps = []
       if (defined(_jar_target_name)) {
         deps += [ ":$_jar_target_name" ]
diff --git a/build/config/arm.gni b/build/config/arm.gni
index 865f642..29434eb 100644
--- a/build/config/arm.gni
+++ b/build/config/arm.gni
@@ -69,6 +69,7 @@
       arm_fpu = "vfp"
     }
     arm_use_thumb = false
+    arm_use_neon = false
   } else if (arm_version == 7) {
     if (arm_arch == "") {
       arm_arch = "armv7-a"
diff --git a/build/fuchsia/runner_common.py b/build/fuchsia/runner_common.py
index 21c5c67..b4e40db 100755
--- a/build/fuchsia/runner_common.py
+++ b/build/fuchsia/runner_common.py
@@ -169,6 +169,12 @@
   autorun_file = open(bin_name + '.bootfs_autorun', 'w')
   autorun_file.write('#!/bin/sh\n')
   if _IsRunningOnBot():
+    # We drop to -smp 1 to avoid counterintuitive observations on the realtime
+    # clock, but keep the concurrency at the default of 4. Insert at the
+    # beginning of the list so that if the real command line provides a specific
+    # value later, it will be used.
+    child_args.insert(0, '--test-launcher-jobs=4')
+
     # TODO(scottmg): Passed through for https://crbug.com/755282.
     autorun_file.write('export CHROME_HEADLESS=1\n')
 
diff --git a/build/fuchsia/test_runner.py b/build/fuchsia/test_runner.py
index 24f3808..0aad594 100755
--- a/build/fuchsia/test_runner.py
+++ b/build/fuchsia/test_runner.py
@@ -24,10 +24,6 @@
 sys.path.append(os.path.join(DIR_SOURCE_ROOT, 'build', 'util', 'lib', 'common'))
 import chrome_test_server_spawner
 
-# RunFuchsia() may run qemu with 1 or 4 CPUs. In both cases keep test
-# concurrency set to 4.
-DEFAULT_TEST_CONCURRENCY = 4
-
 
 def IsLocalPortAvailable(port):
   s = socket.socket()
@@ -141,11 +137,9 @@
   if args.test_launcher_batch_limit:
     child_args.append('--test-launcher-batch-limit=%d' %
                        args.test_launcher_batch_limit)
-
-  test_concurrency = args.test_launcher_jobs \
-      if args.test_launcher_jobs else DEFAULT_TEST_CONCURRENCY
-  child_args.append('--test-launcher-jobs=%d' % test_concurrency)
-
+  if args.test_launcher_jobs:
+    child_args.append('--test-launcher-jobs=%d' %
+                       args.test_launcher_jobs)
   if args.gtest_filter:
     child_args.append('--gtest_filter=' + args.gtest_filter)
   if args.gtest_repeat:
@@ -160,7 +154,7 @@
   # Start test server spawner for tests that need it.
   if args.enable_test_server:
     spawning_server = chrome_test_server_spawner.SpawningServer(
-        0, PortForwarderNoop(), test_concurrency)
+        0, PortForwarderNoop())
     spawning_server.Start()
 
     # Generate test server config.
diff --git a/build/secondary/third_party/android_tools/BUILD.gn b/build/secondary/third_party/android_tools/BUILD.gn
index e9e7058..ad2aa67 100644
--- a/build/secondary/third_party/android_tools/BUILD.gn
+++ b/build/secondary/third_party/android_tools/BUILD.gn
@@ -4,14 +4,6 @@
 
 import("//build/config/android/rules.gni")
 
-if (!defined(default_android_support_library_version)) {
-  default_android_support_library_version = "25.0.1"
-}
-
-declare_args() {
-  android_support_library_version = default_android_support_library_version
-}
-
 config("cpu_features_include") {
   include_dirs = [ "$android_ndk_root/sources/android/cpufeatures" ]
 }
@@ -38,238 +30,65 @@
   ]
 }
 
-lib_version = android_support_library_version
-lib_path = "$android_sdk_root/extras/android/m2repository/com/android/support"
-
-android_java_prebuilt("android_gcm_java") {
-  jar_path = "$android_sdk_root/extras/google/gcm/gcm-client/dist/gcm.jar"
+template("support_lib_alias") {
+  java_group(target_name) {
+    forward_variables_from(invoker, [ "testonly" ])
+    deps = [
+      "$android_support_library_package:$target_name",
+    ]
+  }
 }
 
-android_java_prebuilt("emma_device_java") {
-  jar_path = "$android_sdk_root/tools/lib/emma_device.jar"
-  include_java_resources = true
-}
-
-android_aar_prebuilt("android_support_design_java") {
-  deps = [
-    ":android_support_transition_java",
-    ":android_support_v4_java",
-    ":android_support_v7_appcompat_java",
-    ":android_support_v7_recyclerview_java",
-  ]
-  _lib_name = "design"
-  aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar"
-}
-
-android_aar_prebuilt("android_support_transition_java") {
-  deps = [
-    ":android_support_v4_java",
-  ]
-  _lib_name = "transition"
-  aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar"
-}
-
-android_aar_prebuilt("android_support_multidex_java") {
-  aar_path = "$lib_path/multidex/1.0.1/multidex-1.0.1.aar"
-}
-
-android_java_prebuilt("android_support_annotations_java") {
-  _lib_name = "support-annotations"
-  jar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.jar"
-}
-
-java_group("android_support_v4_java") {
-  deps = [
-    ":android_support_compat_java",
-    ":android_support_core_ui_java",
-    ":android_support_core_utils_java",
-    ":android_support_fragment_java",
-    ":android_support_media_compat_java",
-  ]
-}
-
-android_aar_prebuilt("android_support_compat_java") {
-  deps = [
-    ":android_support_annotations_java",
-  ]
-  _lib_name = "support-compat"
-  aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar"
-  ignore_aidl = true  # We don't appear to need these currently.
-}
-
-android_aar_prebuilt("android_support_core_ui_java") {
-  deps = [
-    ":android_support_compat_java",
-  ]
-  _lib_name = "support-core-ui"
-  aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar"
-}
-
-android_aar_prebuilt("android_support_core_utils_java") {
-  deps = [
-    ":android_support_compat_java",
-  ]
-  _lib_name = "support-core-utils"
-  aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar"
-}
-
-android_aar_prebuilt("android_support_fragment_java") {
-  deps = [
-    ":android_support_compat_java",
-    ":android_support_core_ui_java",
-    ":android_support_core_utils_java",
-    ":android_support_media_compat_java",
-  ]
-  _lib_name = "support-fragment"
-  aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar"
-}
-
-android_aar_prebuilt("android_support_media_compat_java") {
-  deps = [
-    ":android_support_compat_java",
-  ]
-  _lib_name = "support-media-compat"
-  aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar"
-  ignore_aidl = true  # We don't appear to need these currently.
-}
-
-android_aar_prebuilt("android_support_v13_java") {
-  deps = [
-    ":android_support_v4_java",
-  ]
-  _lib_name = "support-v13"
-  aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar"
-}
-
-android_aar_prebuilt("android_support_vector_drawable_java") {
-  deps = [
-    ":android_support_compat_java",
-  ]
-  _lib_name = "support-vector-drawable"
-  aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar"
-}
-
-android_aar_prebuilt("android_support_v7_appcompat_java_internal") {
-  deps = [
-    ":android_support_v4_java",
-  ]
-  _lib_name = "appcompat-v7"
-  aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar"
-}
-
-java_group("android_support_v7_appcompat_java") {
-  deps = [
-    ":android_support_v4_java",
-    ":android_support_v7_appcompat_java_internal",
-    ":android_support_vector_drawable_java",
-  ]
-}
-
-android_aar_prebuilt("android_support_v7_gridlayout_java") {
-  deps = [
-    ":android_support_compat_java",
-    ":android_support_core_ui_java",
-  ]
-  _lib_name = "gridlayout-v7"
-  aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar"
-}
-
-android_aar_prebuilt("android_support_v7_mediarouter_java") {
-  deps = [
-    ":android_support_v7_appcompat_java",
-    ":android_support_v7_palette_java",
-  ]
-  _lib_name = "mediarouter-v7"
-  aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar"
-}
-
-android_aar_prebuilt("android_support_v7_recyclerview_java") {
-  deps = [
-    ":android_support_annotations_java",
-    ":android_support_compat_java",
-    ":android_support_core_ui_java",
-  ]
-  _lib_name = "recyclerview-v7"
-  aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar"
-}
-
-android_aar_prebuilt("android_support_v7_palette_java") {
-  deps = [
-    ":android_support_compat_java",
-    ":android_support_core_utils_java",
-  ]
-  _lib_name = "palette-v7"
-  aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar"
-}
-
-android_aar_prebuilt("android_support_v7_preference_java") {
-  deps = [
-    ":android_support_v4_java",
-    ":android_support_v7_appcompat_java",
-    ":android_support_v7_recyclerview_java",
-  ]
-  _lib_name = "preference-v7"
-  aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar"
-}
-
-android_aar_prebuilt("android_support_v14_preference_java") {
-  deps = [
-    ":android_support_v4_java",
-    ":android_support_v7_appcompat_java",
-    ":android_support_v7_preference_java",
-    ":android_support_v7_recyclerview_java",
-  ]
-  _lib_name = "preference-v14"
-  aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar"
-}
-
-android_aar_prebuilt("android_support_v17_leanback_java") {
-  deps = [
-    ":android_support_v4_java",
-    ":android_support_v7_recyclerview_java",
-  ]
-  _lib_name = "leanback-v17"
-  aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar"
-}
-
-android_aar_prebuilt("android_support_v17_preference_java") {
-  deps = [
-    ":android_support_v14_preference_java",
-    ":android_support_v17_leanback_java",
-    ":android_support_v4_java",
-    ":android_support_v7_appcompat_java",
-    ":android_support_v7_preference_java",
-    ":android_support_v7_recyclerview_java",
-  ]
-  _lib_name = "preference-leanback-v17"
-  aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar"
-}
-
-android_library("android_support_chromium_java") {
+support_lib_alias("android_support_chromium_java") {
   testonly = true
-  java_files = [ "$android_sdk_root/extras/chromium/support/src/org/chromium/android/support/PackageManagerWrapper.java" ]
 }
-
-# TODO(dgn): Remove this once no other target has a dependency on it
-java_group("google_play_services_default_resources") {
-  deps = []
+support_lib_alias("android_gcm_java") {
 }
-
-# TODO(dgn): Remove this once other targets register dependencies on only the
-# modules they need.
-java_group("google_play_services_default_java") {
-  deps = [
-    ":google_play_services_auth_base_java",
-    ":google_play_services_auth_java",
-    ":google_play_services_base_java",
-    ":google_play_services_basement_java",
-    ":google_play_services_cast_java",
-    ":google_play_services_gcm_java",
-    ":google_play_services_iid_java",
-    ":google_play_services_location_java",
-    ":google_play_services_nearby_java",
-    ":google_play_services_vision_java",
-  ]
+support_lib_alias("emma_device_java") {
+}
+support_lib_alias("android_support_multidex_java") {
+}
+support_lib_alias("android_support_annotations_java") {
+}
+support_lib_alias("android_support_compat_java") {
+}
+support_lib_alias("android_support_core_ui_java") {
+}
+support_lib_alias("android_support_core_utils_java") {
+}
+support_lib_alias("android_support_design_java") {
+}
+support_lib_alias("android_support_fragment_java") {
+}
+support_lib_alias("android_support_media_compat_java") {
+}
+support_lib_alias("android_support_transition_java") {
+}
+support_lib_alias("android_support_v4_java") {
+}
+support_lib_alias("android_support_v7_appcompat_java") {
+}
+support_lib_alias("android_support_v7_appcompat_java_internal") {
+}
+support_lib_alias("android_support_v7_gridlayout_java") {
+}
+support_lib_alias("android_support_v7_mediarouter_java") {
+}
+support_lib_alias("android_support_v7_palette_java") {
+}
+support_lib_alias("android_support_v7_preference_java") {
+}
+support_lib_alias("android_support_v7_recyclerview_java") {
+}
+support_lib_alias("android_support_v13_java") {
+}
+support_lib_alias("android_support_v14_preference_java") {
+}
+support_lib_alias("android_support_v17_leanback_java") {
+}
+support_lib_alias("android_support_v17_preference_java") {
+}
+support_lib_alias("android_support_vector_drawable_java") {
 }
 
 # TODO(dgn): Use the POM files instead of hardcoding the dependencies.
@@ -282,6 +101,7 @@
   ]
   _lib_name = "play-services-basement"
   aar_path = "$gms_path/$_lib_name/$gms_version/$_lib_name-$gms_version.aar"
+  info_path = "//build/secondary/third_party/android_tools/$target_name.info"
   input_jars_paths = [ "$android_sdk/optional/org.apache.http.legacy.jar" ]
 }
 
@@ -291,6 +111,7 @@
   ]
   _lib_name = "play-services-tasks"
   aar_path = "$gms_path/$_lib_name/$gms_version/$_lib_name-$gms_version.aar"
+  info_path = "//build/secondary/third_party/android_tools/$target_name.info"
 }
 
 android_aar_prebuilt("google_play_services_base_java") {
@@ -301,6 +122,7 @@
   ]
   _lib_name = "play-services-base"
   aar_path = "$gms_path/$_lib_name/$gms_version/$_lib_name-$gms_version.aar"
+  info_path = "//build/secondary/third_party/android_tools/$target_name.info"
 }
 
 android_aar_prebuilt("google_play_services_auth_base_java") {
@@ -310,6 +132,7 @@
   ]
   _lib_name = "play-services-auth-base"
   aar_path = "$gms_path/$_lib_name/$gms_version/$_lib_name-$gms_version.aar"
+  info_path = "//build/secondary/third_party/android_tools/$target_name.info"
 }
 
 android_aar_prebuilt("google_play_services_auth_java") {
@@ -320,6 +143,7 @@
   ]
   _lib_name = "play-services-auth"
   aar_path = "$gms_path/$_lib_name/$gms_version/$_lib_name-$gms_version.aar"
+  info_path = "//build/secondary/third_party/android_tools/$target_name.info"
 }
 
 android_aar_prebuilt("google_play_services_cast_java") {
@@ -330,6 +154,7 @@
   ]
   _lib_name = "play-services-cast"
   aar_path = "$gms_path/$_lib_name/$gms_version/$_lib_name-$gms_version.aar"
+  info_path = "//build/secondary/third_party/android_tools/$target_name.info"
 }
 
 android_aar_prebuilt("google_play_services_iid_java") {
@@ -339,6 +164,7 @@
   ]
   _lib_name = "play-services-iid"
   aar_path = "$gms_path/$_lib_name/$gms_version/$_lib_name-$gms_version.aar"
+  info_path = "//build/secondary/third_party/android_tools/$target_name.info"
 }
 
 android_aar_prebuilt("google_play_services_gcm_java") {
@@ -349,6 +175,7 @@
   ]
   _lib_name = "play-services-gcm"
   aar_path = "$gms_path/$_lib_name/$gms_version/$_lib_name-$gms_version.aar"
+  info_path = "//build/secondary/third_party/android_tools/$target_name.info"
 }
 
 android_aar_prebuilt("google_play_services_location_java") {
@@ -358,6 +185,7 @@
   ]
   _lib_name = "play-services-location"
   aar_path = "$gms_path/$_lib_name/$gms_version/$_lib_name-$gms_version.aar"
+  info_path = "//build/secondary/third_party/android_tools/$target_name.info"
 }
 
 android_aar_prebuilt("google_play_services_nearby_java") {
@@ -367,6 +195,7 @@
   ]
   _lib_name = "play-services-nearby"
   aar_path = "$gms_path/$_lib_name/$gms_version/$_lib_name-$gms_version.aar"
+  info_path = "//build/secondary/third_party/android_tools/$target_name.info"
 }
 
 android_aar_prebuilt("google_play_services_vision_java") {
@@ -376,6 +205,7 @@
   ]
   _lib_name = "play-services-vision"
   aar_path = "$gms_path/$_lib_name/$gms_version/$_lib_name-$gms_version.aar"
+  info_path = "//build/secondary/third_party/android_tools/$target_name.info"
 }
 
 # TODO(paulmiller): Replace this with a proper target after rolling to a GMS
diff --git a/build/secondary/third_party/android_tools/google_play_services_auth_base_java.info b/build/secondary/third_party/android_tools/google_play_services_auth_base_java.info
new file mode 100644
index 0000000..0dfcb237
--- /dev/null
+++ b/build/secondary/third_party/android_tools/google_play_services_auth_base_java.info
@@ -0,0 +1,13 @@
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+aidl = [  ]
+assets = [  ]
+has_classes_jar = true
+has_native_libraries = false
+has_proguard_flags = true
+has_r_text_file = false
+is_manifest_empty = true
+resources = [  ]
+subjar_tuples = [  ]
+subjars = [  ]
diff --git a/build/secondary/third_party/android_tools/google_play_services_auth_java.info b/build/secondary/third_party/android_tools/google_play_services_auth_java.info
new file mode 100644
index 0000000..acf40e8
--- /dev/null
+++ b/build/secondary/third_party/android_tools/google_play_services_auth_java.info
@@ -0,0 +1,13 @@
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+aidl = [  ]
+assets = [  ]
+has_classes_jar = true
+has_native_libraries = false
+has_proguard_flags = true
+has_r_text_file = false
+is_manifest_empty = false
+resources = [  ]
+subjar_tuples = [  ]
+subjars = [  ]
diff --git a/build/secondary/third_party/android_tools/google_play_services_base_java.info b/build/secondary/third_party/android_tools/google_play_services_base_java.info
new file mode 100644
index 0000000..0a0aeb4
--- /dev/null
+++ b/build/secondary/third_party/android_tools/google_play_services_base_java.info
@@ -0,0 +1,13 @@
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+aidl = [  ]
+assets = [  ]
+has_classes_jar = true
+has_native_libraries = false
+has_proguard_flags = true
+has_r_text_file = false
+is_manifest_empty = false
+resources = [ "res/color/common_google_signin_btn_text_dark.xml", "res/color/common_google_signin_btn_text_light.xml", "res/color/common_google_signin_btn_tint.xml", "res/drawable-hdpi-v4/common_full_open_on_phone.png", "res/drawable-hdpi-v4/common_google_signin_btn_icon_dark_normal_background.9.png", "res/drawable-hdpi-v4/common_google_signin_btn_icon_light_normal_background.9.png", "res/drawable-hdpi-v4/common_google_signin_btn_text_dark_normal_background.9.png", "res/drawable-hdpi-v4/common_google_signin_btn_text_light_normal_background.9.png", "res/drawable-hdpi-v4/googleg_disabled_color_18.png", "res/drawable-hdpi-v4/googleg_standard_color_18.png", "res/drawable-mdpi-v4/common_google_signin_btn_icon_dark_normal_background.9.png", "res/drawable-mdpi-v4/common_google_signin_btn_icon_light_normal_background.9.png", "res/drawable-mdpi-v4/common_google_signin_btn_text_dark_normal_background.9.png", "res/drawable-mdpi-v4/common_google_signin_btn_text_light_normal_background.9.png", "res/drawable-mdpi-v4/googleg_disabled_color_18.png", "res/drawable-mdpi-v4/googleg_standard_color_18.png", "res/drawable-xhdpi-v4/common_full_open_on_phone.png", "res/drawable-xhdpi-v4/common_google_signin_btn_icon_dark_normal_background.9.png", "res/drawable-xhdpi-v4/common_google_signin_btn_icon_light_normal_background.9.png", "res/drawable-xhdpi-v4/common_google_signin_btn_text_dark_normal_background.9.png", "res/drawable-xhdpi-v4/common_google_signin_btn_text_light_normal_background.9.png", "res/drawable-xhdpi-v4/googleg_disabled_color_18.png", "res/drawable-xhdpi-v4/googleg_standard_color_18.png", "res/drawable-xxhdpi-v4/common_google_signin_btn_icon_dark_normal_background.9.png", "res/drawable-xxhdpi-v4/common_google_signin_btn_icon_light_normal_background.9.png", "res/drawable-xxhdpi-v4/common_google_signin_btn_text_dark_normal_background.9.png", "res/drawable-xxhdpi-v4/common_google_signin_btn_text_light_normal_background.9.png", "res/drawable-xxhdpi-v4/googleg_disabled_color_18.png", "res/drawable-xxhdpi-v4/googleg_standard_color_18.png", "res/drawable/common_google_signin_btn_icon_dark.xml", "res/drawable/common_google_signin_btn_icon_dark_focused.xml", "res/drawable/common_google_signin_btn_icon_dark_normal.xml", "res/drawable/common_google_signin_btn_icon_disabled.xml", "res/drawable/common_google_signin_btn_icon_light.xml", "res/drawable/common_google_signin_btn_icon_light_focused.xml", "res/drawable/common_google_signin_btn_icon_light_normal.xml", "res/drawable/common_google_signin_btn_text_dark.xml", "res/drawable/common_google_signin_btn_text_dark_focused.xml", "res/drawable/common_google_signin_btn_text_dark_normal.xml", "res/drawable/common_google_signin_btn_text_disabled.xml", "res/drawable/common_google_signin_btn_text_light.xml", "res/drawable/common_google_signin_btn_text_light_focused.xml", "res/drawable/common_google_signin_btn_text_light_normal.xml", "res/values-af/values.xml", "res/values-am/values.xml", "res/values-ar/values.xml", "res/values-az/values.xml", "res/values-be/values.xml", "res/values-bg/values.xml", "res/values-bn/values.xml", "res/values-bs/values.xml", "res/values-ca/values.xml", "res/values-cs/values.xml", "res/values-da/values.xml", "res/values-de/values.xml", "res/values-el/values.xml", "res/values-en-rGB/values.xml", "res/values-es-rUS/values.xml", "res/values-es/values.xml", "res/values-et/values.xml", "res/values-eu/values.xml", "res/values-fa/values.xml", "res/values-fi/values.xml", "res/values-fr-rCA/values.xml", "res/values-fr/values.xml", "res/values-gl/values.xml", "res/values-gu/values.xml", "res/values-hi/values.xml", "res/values-hr/values.xml", "res/values-hu/values.xml", "res/values-hy/values.xml", "res/values-in/values.xml", "res/values-is/values.xml", "res/values-it/values.xml", "res/values-iw/values.xml", "res/values-ja/values.xml", "res/values-ka/values.xml", "res/values-kk/values.xml", "res/values-km/values.xml", "res/values-kn/values.xml", "res/values-ko/values.xml", "res/values-ky/values.xml", "res/values-lo/values.xml", "res/values-lt/values.xml", "res/values-lv/values.xml", "res/values-mk/values.xml", "res/values-ml/values.xml", "res/values-mn/values.xml", "res/values-mr/values.xml", "res/values-ms/values.xml", "res/values-my/values.xml", "res/values-nb/values.xml", "res/values-ne/values.xml", "res/values-nl/values.xml", "res/values-pa/values.xml", "res/values-pl/values.xml", "res/values-pt-rBR/values.xml", "res/values-pt-rPT/values.xml", "res/values-ro/values.xml", "res/values-ru/values.xml", "res/values-si/values.xml", "res/values-sk/values.xml", "res/values-sl/values.xml", "res/values-sq/values.xml", "res/values-sr/values.xml", "res/values-sv/values.xml", "res/values-sw/values.xml", "res/values-ta/values.xml", "res/values-te/values.xml", "res/values-th/values.xml", "res/values-tl/values.xml", "res/values-tr/values.xml", "res/values-uk/values.xml", "res/values-ur/values.xml", "res/values-uz/values.xml", "res/values-vi/values.xml", "res/values-zh-rCN/values.xml", "res/values-zh-rHK/values.xml", "res/values-zh-rTW/values.xml", "res/values-zu/values.xml", "res/values/values.xml" ]
+subjar_tuples = [  ]
+subjars = [  ]
diff --git a/build/secondary/third_party/android_tools/google_play_services_basement_java.info b/build/secondary/third_party/android_tools/google_play_services_basement_java.info
new file mode 100644
index 0000000..19c75ad
--- /dev/null
+++ b/build/secondary/third_party/android_tools/google_play_services_basement_java.info
@@ -0,0 +1,13 @@
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+aidl = [  ]
+assets = [  ]
+has_classes_jar = true
+has_native_libraries = false
+has_proguard_flags = true
+has_r_text_file = true
+is_manifest_empty = false
+resources = [ "res/values-af/values.xml", "res/values-am/values.xml", "res/values-ar/values.xml", "res/values-az/values.xml", "res/values-be/values.xml", "res/values-bg/values.xml", "res/values-bn/values.xml", "res/values-bs/values.xml", "res/values-ca/values.xml", "res/values-cs/values.xml", "res/values-da/values.xml", "res/values-de/values.xml", "res/values-el/values.xml", "res/values-en-rGB/values.xml", "res/values-es-rUS/values.xml", "res/values-es/values.xml", "res/values-et/values.xml", "res/values-eu/values.xml", "res/values-fa/values.xml", "res/values-fi/values.xml", "res/values-fr-rCA/values.xml", "res/values-fr/values.xml", "res/values-gl/values.xml", "res/values-gu/values.xml", "res/values-hi/values.xml", "res/values-hr/values.xml", "res/values-hu/values.xml", "res/values-hy/values.xml", "res/values-in/values.xml", "res/values-is/values.xml", "res/values-it/values.xml", "res/values-iw/values.xml", "res/values-ja/values.xml", "res/values-ka/values.xml", "res/values-kk/values.xml", "res/values-km/values.xml", "res/values-kn/values.xml", "res/values-ko/values.xml", "res/values-ky/values.xml", "res/values-lo/values.xml", "res/values-lt/values.xml", "res/values-lv/values.xml", "res/values-mk/values.xml", "res/values-ml/values.xml", "res/values-mn/values.xml", "res/values-mr/values.xml", "res/values-ms/values.xml", "res/values-my/values.xml", "res/values-nb/values.xml", "res/values-ne/values.xml", "res/values-nl/values.xml", "res/values-pa/values.xml", "res/values-pl/values.xml", "res/values-pt-rBR/values.xml", "res/values-pt-rPT/values.xml", "res/values-ro/values.xml", "res/values-ru/values.xml", "res/values-si/values.xml", "res/values-sk/values.xml", "res/values-sl/values.xml", "res/values-sq/values.xml", "res/values-sr/values.xml", "res/values-sv/values.xml", "res/values-sw/values.xml", "res/values-ta/values.xml", "res/values-te/values.xml", "res/values-th/values.xml", "res/values-tl/values.xml", "res/values-tr/values.xml", "res/values-uk/values.xml", "res/values-ur/values.xml", "res/values-uz/values.xml", "res/values-vi/values.xml", "res/values-zh-rCN/values.xml", "res/values-zh-rHK/values.xml", "res/values-zh-rTW/values.xml", "res/values-zu/values.xml", "res/values/values.xml" ]
+subjar_tuples = [  ]
+subjars = [  ]
diff --git a/build/secondary/third_party/android_tools/google_play_services_cast_java.info b/build/secondary/third_party/android_tools/google_play_services_cast_java.info
new file mode 100644
index 0000000..913e27b
--- /dev/null
+++ b/build/secondary/third_party/android_tools/google_play_services_cast_java.info
@@ -0,0 +1,13 @@
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+aidl = [  ]
+assets = [  ]
+has_classes_jar = true
+has_native_libraries = false
+has_proguard_flags = true
+has_r_text_file = false
+is_manifest_empty = true
+resources = [ "res/drawable-hdpi-v4/cast_ic_notification_0.png", "res/drawable-hdpi-v4/cast_ic_notification_1.png", "res/drawable-hdpi-v4/cast_ic_notification_2.png", "res/drawable-hdpi-v4/cast_ic_notification_on.png", "res/drawable-mdpi-v4/cast_ic_notification_0.png", "res/drawable-mdpi-v4/cast_ic_notification_1.png", "res/drawable-mdpi-v4/cast_ic_notification_2.png", "res/drawable-mdpi-v4/cast_ic_notification_on.png", "res/drawable-xhdpi-v4/cast_ic_notification_0.png", "res/drawable-xhdpi-v4/cast_ic_notification_1.png", "res/drawable-xhdpi-v4/cast_ic_notification_2.png", "res/drawable-xhdpi-v4/cast_ic_notification_on.png", "res/drawable-xxhdpi-v4/cast_ic_notification_0.png", "res/drawable-xxhdpi-v4/cast_ic_notification_1.png", "res/drawable-xxhdpi-v4/cast_ic_notification_2.png", "res/drawable-xxhdpi-v4/cast_ic_notification_on.png", "res/drawable/cast_ic_notification_connecting.xml", "res/values-af/values.xml", "res/values-am/values.xml", "res/values-ar/values.xml", "res/values-az/values.xml", "res/values-be/values.xml", "res/values-bg/values.xml", "res/values-bn/values.xml", "res/values-bs/values.xml", "res/values-ca/values.xml", "res/values-cs/values.xml", "res/values-da/values.xml", "res/values-de/values.xml", "res/values-el/values.xml", "res/values-en-rGB/values.xml", "res/values-es-rUS/values.xml", "res/values-es/values.xml", "res/values-et/values.xml", "res/values-eu/values.xml", "res/values-fa/values.xml", "res/values-fi/values.xml", "res/values-fr-rCA/values.xml", "res/values-fr/values.xml", "res/values-gl/values.xml", "res/values-gu/values.xml", "res/values-hi/values.xml", "res/values-hr/values.xml", "res/values-hu/values.xml", "res/values-hy/values.xml", "res/values-in/values.xml", "res/values-is/values.xml", "res/values-it/values.xml", "res/values-iw/values.xml", "res/values-ja/values.xml", "res/values-ka/values.xml", "res/values-kk/values.xml", "res/values-km/values.xml", "res/values-kn/values.xml", "res/values-ko/values.xml", "res/values-ky/values.xml", "res/values-lo/values.xml", "res/values-lt/values.xml", "res/values-lv/values.xml", "res/values-mk/values.xml", "res/values-ml/values.xml", "res/values-mn/values.xml", "res/values-mr/values.xml", "res/values-ms/values.xml", "res/values-my/values.xml", "res/values-nb/values.xml", "res/values-ne/values.xml", "res/values-nl/values.xml", "res/values-pa/values.xml", "res/values-pl/values.xml", "res/values-pt-rBR/values.xml", "res/values-pt-rPT/values.xml", "res/values-ro/values.xml", "res/values-ru/values.xml", "res/values-si/values.xml", "res/values-sk/values.xml", "res/values-sl/values.xml", "res/values-sq/values.xml", "res/values-sr/values.xml", "res/values-sv/values.xml", "res/values-sw/values.xml", "res/values-ta/values.xml", "res/values-te/values.xml", "res/values-th/values.xml", "res/values-tl/values.xml", "res/values-tr/values.xml", "res/values-uk/values.xml", "res/values-ur/values.xml", "res/values-uz/values.xml", "res/values-vi/values.xml", "res/values-zh-rCN/values.xml", "res/values-zh-rHK/values.xml", "res/values-zh-rTW/values.xml", "res/values-zu/values.xml", "res/values/values.xml" ]
+subjar_tuples = [  ]
+subjars = [  ]
diff --git a/build/secondary/third_party/android_tools/google_play_services_gcm_java.info b/build/secondary/third_party/android_tools/google_play_services_gcm_java.info
new file mode 100644
index 0000000..acf40e8
--- /dev/null
+++ b/build/secondary/third_party/android_tools/google_play_services_gcm_java.info
@@ -0,0 +1,13 @@
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+aidl = [  ]
+assets = [  ]
+has_classes_jar = true
+has_native_libraries = false
+has_proguard_flags = true
+has_r_text_file = false
+is_manifest_empty = false
+resources = [  ]
+subjar_tuples = [  ]
+subjars = [  ]
diff --git a/build/secondary/third_party/android_tools/google_play_services_iid_java.info b/build/secondary/third_party/android_tools/google_play_services_iid_java.info
new file mode 100644
index 0000000..acf40e8
--- /dev/null
+++ b/build/secondary/third_party/android_tools/google_play_services_iid_java.info
@@ -0,0 +1,13 @@
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+aidl = [  ]
+assets = [  ]
+has_classes_jar = true
+has_native_libraries = false
+has_proguard_flags = true
+has_r_text_file = false
+is_manifest_empty = false
+resources = [  ]
+subjar_tuples = [  ]
+subjars = [  ]
diff --git a/build/secondary/third_party/android_tools/google_play_services_location_java.info b/build/secondary/third_party/android_tools/google_play_services_location_java.info
new file mode 100644
index 0000000..0dfcb237
--- /dev/null
+++ b/build/secondary/third_party/android_tools/google_play_services_location_java.info
@@ -0,0 +1,13 @@
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+aidl = [  ]
+assets = [  ]
+has_classes_jar = true
+has_native_libraries = false
+has_proguard_flags = true
+has_r_text_file = false
+is_manifest_empty = true
+resources = [  ]
+subjar_tuples = [  ]
+subjars = [  ]
diff --git a/build/secondary/third_party/android_tools/google_play_services_nearby_java.info b/build/secondary/third_party/android_tools/google_play_services_nearby_java.info
new file mode 100644
index 0000000..acf40e8
--- /dev/null
+++ b/build/secondary/third_party/android_tools/google_play_services_nearby_java.info
@@ -0,0 +1,13 @@
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+aidl = [  ]
+assets = [  ]
+has_classes_jar = true
+has_native_libraries = false
+has_proguard_flags = true
+has_r_text_file = false
+is_manifest_empty = false
+resources = [  ]
+subjar_tuples = [  ]
+subjars = [  ]
diff --git a/build/secondary/third_party/android_tools/google_play_services_tasks_java.info b/build/secondary/third_party/android_tools/google_play_services_tasks_java.info
new file mode 100644
index 0000000..0dfcb237
--- /dev/null
+++ b/build/secondary/third_party/android_tools/google_play_services_tasks_java.info
@@ -0,0 +1,13 @@
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+aidl = [  ]
+assets = [  ]
+has_classes_jar = true
+has_native_libraries = false
+has_proguard_flags = true
+has_r_text_file = false
+is_manifest_empty = true
+resources = [  ]
+subjar_tuples = [  ]
+subjars = [  ]
diff --git a/build/secondary/third_party/android_tools/google_play_services_vision_java.info b/build/secondary/third_party/android_tools/google_play_services_vision_java.info
new file mode 100644
index 0000000..0dfcb237
--- /dev/null
+++ b/build/secondary/third_party/android_tools/google_play_services_vision_java.info
@@ -0,0 +1,13 @@
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+aidl = [  ]
+assets = [  ]
+has_classes_jar = true
+has_native_libraries = false
+has_proguard_flags = true
+has_r_text_file = false
+is_manifest_empty = true
+resources = [  ]
+subjar_tuples = [  ]
+subjars = [  ]
diff --git a/build/secondary/third_party/android_tools/support/BUILD.gn b/build/secondary/third_party/android_tools/support/BUILD.gn
new file mode 100644
index 0000000..7adaf39
--- /dev/null
+++ b/build/secondary/third_party/android_tools/support/BUILD.gn
@@ -0,0 +1,242 @@
+# 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/android/rules.gni")
+
+visibility = [
+  ":*",
+  "//third_party/android_tools:*",
+]
+
+lib_version = "25.0.1"
+lib_path = "//third_party/android_tools/sdk/extras/android/m2repository/com/android/support"
+build_file_dir = "//build/secondary/third_party/android_tools/support"
+
+android_library("android_support_chromium_java") {
+  testonly = true
+  java_files = [ "//third_party/android_tools/sdk/extras/chromium/support/src/org/chromium/android/support/PackageManagerWrapper.java" ]
+}
+
+android_java_prebuilt("android_gcm_java") {
+  jar_path = "//third_party/android_tools/sdk/extras/google/gcm/gcm-client/dist/gcm.jar"
+}
+
+android_java_prebuilt("emma_device_java") {
+  jar_path = "//third_party/android_tools/sdk/tools/lib/emma_device.jar"
+  include_java_resources = true
+}
+
+android_aar_prebuilt("android_support_design_java") {
+  deps = [
+    ":android_support_transition_java",
+    ":android_support_v4_java",
+    ":android_support_v7_appcompat_java",
+    ":android_support_v7_recyclerview_java",
+  ]
+  _lib_name = "design"
+  aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar"
+  info_path = "$build_file_dir/$target_name.info"
+}
+
+android_aar_prebuilt("android_support_transition_java") {
+  deps = [
+    ":android_support_v4_java",
+  ]
+  _lib_name = "transition"
+  aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar"
+  info_path = "$build_file_dir/$target_name.info"
+}
+
+android_aar_prebuilt("android_support_multidex_java") {
+  aar_path = "$lib_path/multidex/1.0.1/multidex-1.0.1.aar"
+  info_path = "$build_file_dir/$target_name.info"
+}
+
+android_java_prebuilt("android_support_annotations_java") {
+  _lib_name = "support-annotations"
+  jar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.jar"
+}
+
+java_group("android_support_v4_java") {
+  deps = [
+    ":android_support_compat_java",
+    ":android_support_core_ui_java",
+    ":android_support_core_utils_java",
+    ":android_support_fragment_java",
+    ":android_support_media_compat_java",
+  ]
+}
+
+android_aar_prebuilt("android_support_compat_java") {
+  deps = [
+    ":android_support_annotations_java",
+  ]
+  _lib_name = "support-compat"
+  aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar"
+  info_path = "$build_file_dir/$target_name.info"
+  ignore_aidl = true  # We don't appear to need these currently.
+}
+
+android_aar_prebuilt("android_support_core_ui_java") {
+  deps = [
+    ":android_support_compat_java",
+  ]
+  _lib_name = "support-core-ui"
+  aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar"
+  info_path = "$build_file_dir/$target_name.info"
+}
+
+android_aar_prebuilt("android_support_core_utils_java") {
+  deps = [
+    ":android_support_compat_java",
+  ]
+  _lib_name = "support-core-utils"
+  aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar"
+  info_path = "$build_file_dir/$target_name.info"
+}
+
+android_aar_prebuilt("android_support_fragment_java") {
+  deps = [
+    ":android_support_compat_java",
+    ":android_support_core_ui_java",
+    ":android_support_core_utils_java",
+    ":android_support_media_compat_java",
+  ]
+  _lib_name = "support-fragment"
+  aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar"
+  info_path = "$build_file_dir/$target_name.info"
+}
+
+android_aar_prebuilt("android_support_media_compat_java") {
+  deps = [
+    ":android_support_compat_java",
+  ]
+  _lib_name = "support-media-compat"
+  aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar"
+  info_path = "$build_file_dir/$target_name.info"
+  ignore_aidl = true  # We don't appear to need these currently.
+}
+
+android_aar_prebuilt("android_support_v13_java") {
+  deps = [
+    ":android_support_v4_java",
+  ]
+  _lib_name = "support-v13"
+  aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar"
+  info_path = "$build_file_dir/$target_name.info"
+}
+
+android_aar_prebuilt("android_support_vector_drawable_java") {
+  deps = [
+    ":android_support_compat_java",
+  ]
+  _lib_name = "support-vector-drawable"
+  aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar"
+  info_path = "$build_file_dir/$target_name.info"
+}
+
+android_aar_prebuilt("android_support_v7_appcompat_java_internal") {
+  deps = [
+    ":android_support_v4_java",
+  ]
+  _lib_name = "appcompat-v7"
+  aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar"
+  info_path = "$build_file_dir/$target_name.info"
+}
+
+java_group("android_support_v7_appcompat_java") {
+  deps = [
+    ":android_support_v4_java",
+    ":android_support_v7_appcompat_java_internal",
+    ":android_support_vector_drawable_java",
+  ]
+}
+
+android_aar_prebuilt("android_support_v7_gridlayout_java") {
+  deps = [
+    ":android_support_compat_java",
+    ":android_support_core_ui_java",
+  ]
+  _lib_name = "gridlayout-v7"
+  aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar"
+  info_path = "$build_file_dir/$target_name.info"
+}
+
+android_aar_prebuilt("android_support_v7_mediarouter_java") {
+  deps = [
+    ":android_support_v7_appcompat_java",
+    ":android_support_v7_palette_java",
+  ]
+  _lib_name = "mediarouter-v7"
+  aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar"
+  info_path = "$build_file_dir/$target_name.info"
+}
+
+android_aar_prebuilt("android_support_v7_recyclerview_java") {
+  deps = [
+    ":android_support_annotations_java",
+    ":android_support_compat_java",
+    ":android_support_core_ui_java",
+  ]
+  _lib_name = "recyclerview-v7"
+  aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar"
+  info_path = "$build_file_dir/$target_name.info"
+}
+
+android_aar_prebuilt("android_support_v7_palette_java") {
+  deps = [
+    ":android_support_compat_java",
+    ":android_support_core_utils_java",
+  ]
+  _lib_name = "palette-v7"
+  aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar"
+  info_path = "$build_file_dir/$target_name.info"
+}
+
+android_aar_prebuilt("android_support_v7_preference_java") {
+  deps = [
+    ":android_support_v4_java",
+    ":android_support_v7_appcompat_java",
+    ":android_support_v7_recyclerview_java",
+  ]
+  _lib_name = "preference-v7"
+  aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar"
+  info_path = "$build_file_dir/$target_name.info"
+}
+
+android_aar_prebuilt("android_support_v14_preference_java") {
+  deps = [
+    ":android_support_v4_java",
+    ":android_support_v7_appcompat_java",
+    ":android_support_v7_preference_java",
+    ":android_support_v7_recyclerview_java",
+  ]
+  _lib_name = "preference-v14"
+  aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar"
+  info_path = "$build_file_dir/$target_name.info"
+}
+
+android_aar_prebuilt("android_support_v17_leanback_java") {
+  deps = [
+    ":android_support_v4_java",
+    ":android_support_v7_recyclerview_java",
+  ]
+  _lib_name = "leanback-v17"
+  aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar"
+  info_path = "$build_file_dir/$target_name.info"
+}
+
+android_aar_prebuilt("android_support_v17_preference_java") {
+  deps = [
+    ":android_support_v14_preference_java",
+    ":android_support_v17_leanback_java",
+    ":android_support_v4_java",
+    ":android_support_v7_appcompat_java",
+    ":android_support_v7_preference_java",
+    ":android_support_v7_recyclerview_java",
+  ]
+  _lib_name = "preference-leanback-v17"
+  aar_path = "$lib_path/$_lib_name/$lib_version/$_lib_name-$lib_version.aar"
+  info_path = "$build_file_dir/$target_name.info"
+}
diff --git a/build/secondary/third_party/android_tools/support/android_support_compat_java.info b/build/secondary/third_party/android_tools/support/android_support_compat_java.info
new file mode 100644
index 0000000..b68ec40
--- /dev/null
+++ b/build/secondary/third_party/android_tools/support/android_support_compat_java.info
@@ -0,0 +1,13 @@
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+aidl = [ "aidl/android/support/v4/os/ResultReceiver.aidl" ]
+assets = [  ]
+has_classes_jar = true
+has_native_libraries = false
+has_proguard_flags = false
+has_r_text_file = false
+is_manifest_empty = true
+resources = [  ]
+subjar_tuples = [ [ "internal_impl_25.0.1", "libs/internal_impl-25.0.1.jar" ] ]
+subjars = [ "libs/internal_impl-25.0.1.jar" ]
diff --git a/build/secondary/third_party/android_tools/support/android_support_core_ui_java.info b/build/secondary/third_party/android_tools/support/android_support_core_ui_java.info
new file mode 100644
index 0000000..5f0071dd
--- /dev/null
+++ b/build/secondary/third_party/android_tools/support/android_support_core_ui_java.info
@@ -0,0 +1,13 @@
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+aidl = [  ]
+assets = [  ]
+has_classes_jar = true
+has_native_libraries = false
+has_proguard_flags = true
+has_r_text_file = false
+is_manifest_empty = true
+resources = [  ]
+subjar_tuples = [ [ "internal_impl_25.0.1", "libs/internal_impl-25.0.1.jar" ] ]
+subjars = [ "libs/internal_impl-25.0.1.jar" ]
diff --git a/build/secondary/third_party/android_tools/support/android_support_core_utils_java.info b/build/secondary/third_party/android_tools/support/android_support_core_utils_java.info
new file mode 100644
index 0000000..d82eb75
--- /dev/null
+++ b/build/secondary/third_party/android_tools/support/android_support_core_utils_java.info
@@ -0,0 +1,13 @@
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+aidl = [  ]
+assets = [  ]
+has_classes_jar = true
+has_native_libraries = false
+has_proguard_flags = false
+has_r_text_file = false
+is_manifest_empty = true
+resources = [  ]
+subjar_tuples = [ [ "internal_impl_25.0.1", "libs/internal_impl-25.0.1.jar" ] ]
+subjars = [ "libs/internal_impl-25.0.1.jar" ]
diff --git a/build/secondary/third_party/android_tools/support/android_support_design_java.info b/build/secondary/third_party/android_tools/support/android_support_design_java.info
new file mode 100644
index 0000000..37e2270
--- /dev/null
+++ b/build/secondary/third_party/android_tools/support/android_support_design_java.info
@@ -0,0 +1,13 @@
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+aidl = [  ]
+assets = [  ]
+has_classes_jar = true
+has_native_libraries = false
+has_proguard_flags = true
+has_r_text_file = true
+is_manifest_empty = true
+resources = [ "res/drawable-v21/design_bottom_navigation_item_background.xml", "res/values-v21/values-v21.xml", "res/anim-v21/design_bottom_sheet_slide_out.xml", "res/anim-v21/design_appbar_state_list_animator.xml", "res/anim-v21/design_bottom_sheet_slide_in.xml", "res/anim/design_fab_out.xml", "res/anim/design_bottom_sheet_slide_out.xml", "res/anim/design_snackbar_in.xml", "res/anim/design_fab_in.xml", "res/anim/design_snackbar_out.xml", "res/anim/design_bottom_sheet_slide_in.xml", "res/layout/design_layout_tab_text.xml", "res/layout/design_navigation_item_separator.xml", "res/layout/design_bottom_sheet_dialog.xml", "res/layout/design_layout_snackbar_include.xml", "res/layout/design_text_input_password_icon.xml", "res/layout/design_navigation_menu_item.xml", "res/layout/design_menu_item_action_area.xml", "res/layout/design_navigation_item.xml", "res/layout/design_navigation_item_header.xml", "res/layout/design_layout_snackbar.xml", "res/layout/design_navigation_item_subheader.xml", "res/layout/design_navigation_menu.xml", "res/layout/design_layout_tab_icon.xml", "res/layout/design_bottom_navigation_item.xml", "res/values-sw600dp-v13/values-sw600dp-v13.xml", "res/values-land/values-land.xml", "res/color-v23/design_tint_password_toggle.xml", "res/values/values.xml", "res/layout-sw600dp-v13/design_layout_snackbar.xml", "res/color/design_error.xml", "res/color/design_tint_password_toggle.xml", "res/drawable/design_snackbar_background.xml", "res/drawable/design_fab_background.xml", "res/drawable/design_bottom_navigation_item_background.xml", "res/drawable/design_ic_visibility.xml", "res/drawable/navigation_empty_icon.xml" ]
+subjar_tuples = [  ]
+subjars = [  ]
diff --git a/build/secondary/third_party/android_tools/support/android_support_fragment_java.info b/build/secondary/third_party/android_tools/support/android_support_fragment_java.info
new file mode 100644
index 0000000..d82eb75
--- /dev/null
+++ b/build/secondary/third_party/android_tools/support/android_support_fragment_java.info
@@ -0,0 +1,13 @@
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+aidl = [  ]
+assets = [  ]
+has_classes_jar = true
+has_native_libraries = false
+has_proguard_flags = false
+has_r_text_file = false
+is_manifest_empty = true
+resources = [  ]
+subjar_tuples = [ [ "internal_impl_25.0.1", "libs/internal_impl-25.0.1.jar" ] ]
+subjars = [ "libs/internal_impl-25.0.1.jar" ]
diff --git a/build/secondary/third_party/android_tools/support/android_support_media_compat_java.info b/build/secondary/third_party/android_tools/support/android_support_media_compat_java.info
new file mode 100644
index 0000000..347df34
--- /dev/null
+++ b/build/secondary/third_party/android_tools/support/android_support_media_compat_java.info
@@ -0,0 +1,13 @@
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+aidl = [ "aidl/android/support/v4/media/session/MediaSessionCompat.aidl", "aidl/android/support/v4/media/session/PlaybackStateCompat.aidl", "aidl/android/support/v4/media/session/ParcelableVolumeInfo.aidl", "aidl/android/support/v4/media/RatingCompat.aidl", "aidl/android/support/v4/media/MediaMetadataCompat.aidl" ]
+assets = [  ]
+has_classes_jar = true
+has_native_libraries = false
+has_proguard_flags = false
+has_r_text_file = false
+is_manifest_empty = true
+resources = [  ]
+subjar_tuples = [ [ "internal_impl_25.0.1", "libs/internal_impl-25.0.1.jar" ] ]
+subjars = [ "libs/internal_impl-25.0.1.jar" ]
diff --git a/build/secondary/third_party/android_tools/support/android_support_multidex_java.info b/build/secondary/third_party/android_tools/support/android_support_multidex_java.info
new file mode 100644
index 0000000..a2ebd4a8
--- /dev/null
+++ b/build/secondary/third_party/android_tools/support/android_support_multidex_java.info
@@ -0,0 +1,13 @@
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+aidl = [  ]
+assets = [  ]
+has_classes_jar = true
+has_native_libraries = false
+has_proguard_flags = false
+has_r_text_file = false
+is_manifest_empty = true
+resources = [  ]
+subjar_tuples = [  ]
+subjars = [  ]
diff --git a/build/secondary/third_party/android_tools/support/android_support_transition_java.info b/build/secondary/third_party/android_tools/support/android_support_transition_java.info
new file mode 100644
index 0000000..28c8330
--- /dev/null
+++ b/build/secondary/third_party/android_tools/support/android_support_transition_java.info
@@ -0,0 +1,13 @@
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+aidl = [  ]
+assets = [  ]
+has_classes_jar = true
+has_native_libraries = false
+has_proguard_flags = false
+has_r_text_file = true
+is_manifest_empty = true
+resources = [ "res/values/values.xml" ]
+subjar_tuples = [  ]
+subjars = [  ]
diff --git a/build/secondary/third_party/android_tools/support/android_support_v13_java.info b/build/secondary/third_party/android_tools/support/android_support_v13_java.info
new file mode 100644
index 0000000..d82eb75
--- /dev/null
+++ b/build/secondary/third_party/android_tools/support/android_support_v13_java.info
@@ -0,0 +1,13 @@
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+aidl = [  ]
+assets = [  ]
+has_classes_jar = true
+has_native_libraries = false
+has_proguard_flags = false
+has_r_text_file = false
+is_manifest_empty = true
+resources = [  ]
+subjar_tuples = [ [ "internal_impl_25.0.1", "libs/internal_impl-25.0.1.jar" ] ]
+subjars = [ "libs/internal_impl-25.0.1.jar" ]
diff --git a/build/secondary/third_party/android_tools/support/android_support_v14_preference_java.info b/build/secondary/third_party/android_tools/support/android_support_v14_preference_java.info
new file mode 100644
index 0000000..e7f9be67
--- /dev/null
+++ b/build/secondary/third_party/android_tools/support/android_support_v14_preference_java.info
@@ -0,0 +1,13 @@
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+aidl = [  ]
+assets = [  ]
+has_classes_jar = true
+has_native_libraries = false
+has_proguard_flags = false
+has_r_text_file = true
+is_manifest_empty = true
+resources = [ "res/layout-v17/preference_material.xml", "res/layout-v17/preference_information_material.xml", "res/layout-v17/preference_category_material.xml", "res/layout-v17/preference_dropdown_material.xml", "res/values-v17/values-v17.xml", "res/layout/preference_material.xml", "res/layout/preference_information_material.xml", "res/layout/preference_category_material.xml", "res/layout/preference_dropdown_material.xml", "res/layout/preference_widget_switch.xml", "res/values/values.xml", "res/layout-v21/preference_material.xml", "res/layout-v21/preference_information_material.xml", "res/layout-v21/preference_category_material.xml", "res/layout-v21/preference_dropdown_material.xml", "res/drawable/preference_list_divider_material.xml" ]
+subjar_tuples = [  ]
+subjars = [  ]
diff --git a/build/secondary/third_party/android_tools/support/android_support_v17_leanback_java.info b/build/secondary/third_party/android_tools/support/android_support_v17_leanback_java.info
new file mode 100644
index 0000000..93dae49
--- /dev/null
+++ b/build/secondary/third_party/android_tools/support/android_support_v17_leanback_java.info
@@ -0,0 +1,13 @@
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+aidl = [  ]
+assets = [  ]
+has_classes_jar = true
+has_native_libraries = false
+has_proguard_flags = false
+has_r_text_file = true
+is_manifest_empty = true
+resources = [ "res/values-km-rKH/values-km-rKH.xml", "res/values-nl/values-nl.xml", "res/values-az-rAZ/values-az-rAZ.xml", "res/values-gl-rES/values-gl-rES.xml", "res/values-bg/values-bg.xml", "res/values-ldrtl-v17/values-ldrtl-v17.xml", "res/values-pt-rBR/values-pt-rBR.xml", "res/values-eu-rES/values-eu-rES.xml", "res/values-el/values-el.xml", "res/animator/lb_onboarding_page_indicator_enter.xml", "res/animator/lb_guidedactions_item_unpressed.xml", "res/animator/lb_onboarding_logo_enter.xml", "res/animator/lb_guidedactions_item_pressed.xml", "res/animator/lb_onboarding_start_button_fade_out.xml", "res/animator/lb_playback_rows_fade_out.xml", "res/animator/lb_onboarding_start_button_fade_in.xml", "res/animator/lb_decelerator_4.xml", "res/animator/lb_onboarding_logo_exit.xml", "res/animator/lb_guidedstep_slide_up.xml", "res/animator/lb_onboarding_title_enter.xml", "res/animator/lb_onboarding_page_indicator_fade_out.xml", "res/animator/lb_playback_controls_fade_in.xml", "res/animator/lb_playback_rows_fade_in.xml", "res/animator/lb_playback_description_fade_in.xml", "res/animator/lb_playback_controls_fade_out.xml", "res/animator/lb_onboarding_page_indicator_fade_in.xml", "res/animator/lb_playback_description_fade_out.xml", "res/animator/lb_playback_bg_fade_out.xml", "res/animator/lb_decelerator_2.xml", "res/animator/lb_guidedstep_slide_down.xml", "res/animator/lb_playback_bg_fade_in.xml", "res/animator/lb_onboarding_description_enter.xml", "res/values-mk-rMK/values-mk-rMK.xml", "res/values-af/values-af.xml", "res/raw/lb_voice_open.ogg", "res/raw/lb_voice_no_input.ogg", "res/raw/lb_voice_failure.ogg", "res/raw/lb_voice_success.ogg", "res/drawable-v21/lb_card_foreground.xml", "res/drawable-v21/lb_selectable_item_rounded_rect.xml", "res/drawable-v21/lb_action_bg.xml", "res/drawable-v21/lb_control_button_secondary.xml", "res/drawable-v21/lb_control_button_primary.xml", "res/values-uk/values-uk.xml", "res/transition-v21/lb_vertical_grid_entrance_transition.xml", "res/transition-v21/lb_vertical_grid_enter_transition.xml", "res/transition-v21/lb_browse_headers_in.xml", "res/transition-v21/lb_browse_return_transition.xml", "res/transition-v21/lb_title_in.xml", "res/transition-v21/lb_return_transition.xml", "res/transition-v21/lb_browse_enter_transition.xml", "res/transition-v21/lb_guidedstep_activity_enter.xml", "res/transition-v21/lb_browse_headers_out.xml", "res/transition-v21/lb_shared_element_enter_transition.xml", "res/transition-v21/lb_details_return_transition.xml", "res/transition-v21/lb_shared_element_return_transition.xml", "res/transition-v21/lb_title_out.xml", "res/transition-v21/lb_guidedstep_activity_enter_bottom.xml", "res/transition-v21/lb_enter_transition.xml", "res/transition-v21/lb_vertical_grid_return_transition.xml", "res/transition-v21/lb_browse_entrance_transition.xml", "res/transition-v21/lb_details_enter_transition.xml", "res/values-zu/values-zu.xml", "res/values-et-rEE/values-et-rEE.xml", "res/values-v21/values-v21.xml", "res/values-lo-rLA/values-lo-rLA.xml", "res/drawable-hdpi-v4/lb_ic_search_mic_out.png", "res/drawable-hdpi-v4/lb_ic_sad_cloud.png", "res/drawable-hdpi-v4/lb_in_app_search_shadow_normal.9.png", "res/drawable-hdpi-v4/lb_in_app_search_shadow_focused.9.png", "res/drawable-hdpi-v4/lb_ic_actions_right_arrow.png", "res/drawable-hdpi-v4/lb_action_bg_focused.9.png", "res/drawable-hdpi-v4/lb_in_app_search_bg.9.png", "res/drawable-hdpi-v4/lb_ic_search_mic.png", "res/drawable-hdpi-v4/lb_ic_in_app_search.png", "res/values-v22/values-v22.xml", "res/values-bn-rBD/values-bn-rBD.xml", "res/values-is-rIS/values-is-rIS.xml", "res/values-gu-rIN/values-gu-rIN.xml", "res/drawable-mdpi-v4/lb_ic_search_mic_out.png", "res/drawable-mdpi-v4/lb_ic_sad_cloud.png", "res/drawable-mdpi-v4/lb_in_app_search_shadow_normal.9.png", "res/drawable-mdpi-v4/lb_in_app_search_shadow_focused.9.png", "res/drawable-mdpi-v4/lb_ic_actions_right_arrow.png", "res/drawable-mdpi-v4/lb_action_bg_focused.9.png", "res/drawable-mdpi-v4/lb_in_app_search_bg.9.png", "res/drawable-mdpi-v4/lb_ic_search_mic.png", "res/drawable-mdpi-v4/lb_ic_in_app_search.png", "res/values-pa-rIN/values-pa-rIN.xml", "res/values-mr-rIN/values-mr-rIN.xml", "res/values-ru/values-ru.xml", "res/values-pl/values-pl.xml", "res/values-fa/values-fa.xml", "res/values-be-rBY/values-be-rBY.xml", "res/values-si-rLK/values-si-rLK.xml", "res/values-sv/values-sv.xml", "res/values-my-rMM/values-my-rMM.xml", "res/values-b+sr+Latn/values-b+sr+Latn.xml", "res/values-fr/values-fr.xml", "res/values-uz-rUZ/values-uz-rUZ.xml", "res/values-ms-rMY/values-ms-rMY.xml", "res/values-ka-rGE/values-ka-rGE.xml", "res/values-fi/values-fi.xml", "res/values-fr-rCA/values-fr-rCA.xml", "res/values-ca/values-ca.xml", "res/values-in/values-in.xml", "res/values-vi/values-vi.xml", "res/layout/lb_row_media_item_action.xml", "res/layout/lb_error_fragment.xml", "res/layout/lb_picker.xml", "res/layout/lb_speech_orb.xml", "res/layout/lb_details_fragment.xml", "res/layout/lb_divider.xml", "res/layout/lb_guidedstep_fragment.xml", "res/layout/lb_background_window.xml", "res/layout/lb_rows_fragment.xml", "res/layout/lb_guidedstep_background.xml", "res/layout/lb_details_description.xml", "res/layout/lb_media_item_number_view_flipper.xml", "res/layout/lb_action_1_line.xml", "res/layout/lb_guidedbuttonactions.xml", "res/layout/lb_control_bar.xml", "res/layout/lb_vertical_grid_fragment.xml", "res/layout/lb_headers_fragment.xml", "res/layout/lb_guidance.xml", "res/layout/lb_fullwidth_details_overview_logo.xml", "res/layout/lb_header.xml", "res/layout/lb_browse_fragment.xml", "res/layout/lb_row_header.xml", "res/layout/lb_vertical_grid.xml", "res/layout/lb_control_button_secondary.xml", "res/layout/lb_details_overview.xml", "res/layout/lb_image_card_view_themed_badge_left.xml", "res/layout/lb_search_bar.xml", "res/layout/lb_list_row_hovercard.xml", "res/layout/lb_picker_column.xml", "res/layout/lb_image_card_view_themed_content.xml", "res/layout/lb_playback_now_playing_bars.xml", "res/layout/lb_row_media_item.xml", "res/layout/lb_shadow.xml", "res/layout/lb_picker_item.xml", "res/layout/lb_playback_controls_row.xml", "res/layout/lb_fullwidth_details_overview.xml", "res/layout/lb_guidedactions_item.xml", "res/layout/lb_control_button_primary.xml", "res/layout/lb_section_header.xml", "res/layout/lb_playback_controls.xml", "res/layout/lb_image_card_view_themed_badge_right.xml", "res/layout/lb_picker_separator.xml", "res/layout/lb_title_view.xml", "res/layout/lb_image_card_view.xml", "res/layout/lb_guidedactions_datepicker_item.xml", "res/layout/lb_action_2_lines.xml", "res/layout/lb_guidedactions.xml", "res/layout/lb_search_orb.xml", "res/layout/lb_search_fragment.xml", "res/layout/lb_row_container.xml", "res/layout/lb_list_row.xml", "res/layout/lb_browse_title.xml", "res/layout/lb_media_list_header.xml", "res/layout/lb_onboarding_fragment.xml", "res/layout/lb_image_card_view_themed_title.xml", "res/values-en-rGB/values-en-rGB.xml", "res/values-ja/values-ja.xml", "res/values-zh-rCN/values-zh-rCN.xml", "res/values-am/values-am.xml", "res/values-sq-rAL/values-sq-rAL.xml", "res/values-sl/values-sl.xml", "res/values-de/values-de.xml", "res/values-kk-rKZ/values-kk-rKZ.xml", "res/values-en-rAU/values-en-rAU.xml", "res/values-en-rIN/values-en-rIN.xml", "res/values-zh-rTW/values-zh-rTW.xml", "res/values-sw/values-sw.xml", "res/values-nb/values-nb.xml", "res/values-bs-rBA/values-bs-rBA.xml", "res/values-tr/values-tr.xml", "res/values-kn-rIN/values-kn-rIN.xml", "res/transition-v19/lb_browse_headers_in.xml", "res/transition-v19/lb_browse_headers_out.xml", "res/values-hy-rAM/values-hy-rAM.xml", "res/values-es-rUS/values-es-rUS.xml", "res/values-zh-rHK/values-zh-rHK.xml", "res/values-ko/values-ko.xml", "res/values-pt-rPT/values-pt-rPT.xml", "res/values-iw/values-iw.xml", "res/values-lt/values-lt.xml", "res/values-ro/values-ro.xml", "res/animator-v21/lb_playback_description_fade_out.xml", "res/animator-v21/lb_playback_bg_fade_out.xml", "res/animator-v21/lb_playback_bg_fade_in.xml", "res/values-pt/values-pt.xml", "res/values-ar/values-ar.xml", "res/values-ur-rPK/values-ur-rPK.xml", "res/values-ml-rIN/values-ml-rIN.xml", "res/drawable-xhdpi-v4/lb_ic_replay.png", "res/drawable-xhdpi-v4/lb_ic_nav_arrow.png", "res/drawable-xhdpi-v4/lb_text_dot_two_small.png", "res/drawable-xhdpi-v4/lb_text_dot_one_small.png", "res/drawable-xhdpi-v4/lb_ic_skip_previous.png", "res/drawable-xhdpi-v4/lb_ic_thumb_down.png", "res/drawable-xhdpi-v4/lb_ic_thumb_up_outline.png", "res/drawable-xhdpi-v4/lb_ic_search_mic_out.png", "res/drawable-xhdpi-v4/lb_ic_loop.png", "res/drawable-xhdpi-v4/lb_ic_play_fit.png", "res/drawable-xhdpi-v4/lb_ic_thumb_up.png", "res/drawable-xhdpi-v4/lb_ic_guidedactions_item_chevron.png", "res/drawable-xhdpi-v4/lb_ic_fast_rewind.png", "res/drawable-xhdpi-v4/lb_ic_shuffle.png", "res/drawable-xhdpi-v4/lb_ic_sad_cloud.png", "res/drawable-xhdpi-v4/lb_in_app_search_shadow_normal.9.png", "res/drawable-xhdpi-v4/lb_ic_fast_forward.png", "res/drawable-xhdpi-v4/lb_card_shadow_focused.9.png", "res/drawable-xhdpi-v4/lb_in_app_search_shadow_focused.9.png", "res/drawable-xhdpi-v4/lb_ic_actions_right_arrow.png", "res/drawable-xhdpi-v4/lb_action_bg_focused.9.png", "res/drawable-xhdpi-v4/lb_ic_hq.png", "res/drawable-xhdpi-v4/lb_in_app_search_bg.9.png", "res/drawable-xhdpi-v4/lb_ic_stop.png", "res/drawable-xhdpi-v4/lb_ic_search_mic.png", "res/drawable-xhdpi-v4/lb_card_shadow_normal.9.png", "res/drawable-xhdpi-v4/lb_ic_loop_one.png", "res/drawable-xhdpi-v4/lb_ic_in_app_search.png", "res/drawable-xhdpi-v4/lb_text_dot_one.png", "res/drawable-xhdpi-v4/lb_ic_pip.png", "res/drawable-xhdpi-v4/lb_text_dot_two.png", "res/drawable-xhdpi-v4/lb_ic_more.png", "res/drawable-xhdpi-v4/lb_ic_pause.png", "res/drawable-xhdpi-v4/lb_ic_cc.png", "res/drawable-xhdpi-v4/lb_ic_skip_next.png", "res/drawable-xhdpi-v4/lb_ic_thumb_down_outline.png", "res/drawable-xhdpi-v4/lb_ic_playback_loop.png", "res/drawable-xhdpi-v4/lb_ic_play.png", "res/values/values.xml", "res/values-hr/values-hr.xml", "res/values-mn-rMN/values-mn-rMN.xml", "res/values-da/values-da.xml", "res/values-hi/values-hi.xml", "res/values-it/values-it.xml", "res/values-es/values-es.xml", "res/values-sk/values-sk.xml", "res/values-lv/values-lv.xml", "res/values-ky-rKG/values-ky-rKG.xml", "res/values-hu/values-hu.xml", "res/drawable-xxhdpi-v4/lb_ic_search_mic_out.png", "res/drawable-xxhdpi-v4/lb_ic_sad_cloud.png", "res/drawable-xxhdpi-v4/lb_in_app_search_shadow_normal.9.png", "res/drawable-xxhdpi-v4/lb_in_app_search_shadow_focused.9.png", "res/drawable-xxhdpi-v4/lb_ic_actions_right_arrow.png", "res/drawable-xxhdpi-v4/lb_action_bg_focused.9.png", "res/drawable-xxhdpi-v4/lb_in_app_search_bg.9.png", "res/drawable-xxhdpi-v4/lb_ic_search_mic.png", "res/drawable-xxhdpi-v4/lb_ic_in_app_search.png", "res/values-v19/values-v19.xml", "res/values-th/values-th.xml", "res/values-cs/values-cs.xml", "res/values-sr/values-sr.xml", "res/values-tl/values-tl.xml", "res/values-te-rIN/values-te-rIN.xml", "res/values-ne-rNP/values-ne-rNP.xml", "res/values-ta-rIN/values-ta-rIN.xml", "res/drawable/lb_speech_orb.xml", "res/drawable/lb_playback_progress_bar.xml", "res/drawable/lb_card_foreground.xml", "res/drawable/lb_onboarding_start_button_background.xml", "res/drawable/lb_control_button_secondary.xml", "res/drawable/lb_playback_now_playing_bar.xml", "res/drawable/lb_control_button_primary.xml", "res/drawable/lb_background.xml", "res/drawable/lb_headers_right_fading.xml", "res/drawable/lb_search_orb.xml" ]
+subjar_tuples = [  ]
+subjars = [  ]
diff --git a/build/secondary/third_party/android_tools/support/android_support_v17_preference_java.info b/build/secondary/third_party/android_tools/support/android_support_v17_preference_java.info
new file mode 100644
index 0000000..e97682c1
--- /dev/null
+++ b/build/secondary/third_party/android_tools/support/android_support_v17_preference_java.info
@@ -0,0 +1,13 @@
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+aidl = [  ]
+assets = [  ]
+has_classes_jar = true
+has_native_libraries = false
+has_proguard_flags = false
+has_r_text_file = true
+is_manifest_empty = true
+resources = [ "res/layout/leanback_preference_category.xml", "res/layout/leanback_list_preference_item_single.xml", "res/layout/leanback_list_preference_fragment.xml", "res/layout/leanback_list_preference_item_multi.xml", "res/layout/leanback_settings_fragment.xml", "res/layout/leanback_preference_fragment.xml", "res/layout/leanback_preferences_list.xml", "res/layout/leanback_preference_information.xml", "res/layout/leanback_preference.xml", "res/values/values.xml", "res/layout-v21/leanback_settings_fragment.xml", "res/color/lb_preference_item_secondary_text_color.xml", "res/color/lb_preference_item_primary_text_color.xml" ]
+subjar_tuples = [  ]
+subjars = [  ]
diff --git a/build/secondary/third_party/android_tools/support/android_support_v7_appcompat_java_internal.info b/build/secondary/third_party/android_tools/support/android_support_v7_appcompat_java_internal.info
new file mode 100644
index 0000000..780717bb
--- /dev/null
+++ b/build/secondary/third_party/android_tools/support/android_support_v7_appcompat_java_internal.info
@@ -0,0 +1,13 @@
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+aidl = [  ]
+assets = [  ]
+has_classes_jar = true
+has_native_libraries = false
+has_proguard_flags = false
+has_r_text_file = true
+is_manifest_empty = true
+resources = [ "res/values-v23/values-v23.xml", "res/values-km-rKH/values-km-rKH.xml", "res/values-nl/values-nl.xml", "res/values-az-rAZ/values-az-rAZ.xml", "res/values-port/values-port.xml", "res/values-gl-rES/values-gl-rES.xml", "res/values-bg/values-bg.xml", "res/values-v18/values-v18.xml", "res/values-xlarge-v4/values-xlarge-v4.xml", "res/values-pt-rBR/values-pt-rBR.xml", "res/values-eu-rES/values-eu-rES.xml", "res/values-el/values-el.xml", "res/values-mk-rMK/values-mk-rMK.xml", "res/values-af/values-af.xml", "res/drawable-ldrtl-xhdpi-v17/abc_spinner_mtrl_am_alpha.9.png", "res/drawable-ldrtl-xhdpi-v17/abc_ic_menu_copy_mtrl_am_alpha.png", "res/drawable-ldrtl-xhdpi-v17/abc_ic_menu_cut_mtrl_alpha.png", "res/drawable-ldrtl-xxxhdpi-v17/abc_spinner_mtrl_am_alpha.9.png", "res/drawable-ldrtl-xxxhdpi-v17/abc_ic_menu_copy_mtrl_am_alpha.png", "res/drawable-ldrtl-xxxhdpi-v17/abc_ic_menu_cut_mtrl_alpha.png", "res/drawable-v21/abc_btn_colored_material.xml", "res/drawable-v21/abc_edit_text_material.xml", "res/drawable-v21/notification_action_background.xml", "res/drawable-v21/abc_action_bar_item_background_material.xml", "res/values-uk/values-uk.xml", "res/values-zu/values-zu.xml", "res/values-et-rEE/values-et-rEE.xml", "res/values-v21/values-v21.xml", "res/values-lo-rLA/values-lo-rLA.xml", "res/drawable-hdpi-v4/abc_ic_menu_share_mtrl_alpha.png", "res/drawable-hdpi-v4/abc_list_pressed_holo_light.9.png", "res/drawable-hdpi-v4/abc_btn_switch_to_on_mtrl_00012.9.png", "res/drawable-hdpi-v4/abc_scrubber_control_off_mtrl_alpha.png", "res/drawable-hdpi-v4/abc_list_focused_holo.9.png", "res/drawable-hdpi-v4/abc_menu_hardkey_panel_mtrl_mult.9.png", "res/drawable-hdpi-v4/abc_textfield_activated_mtrl_alpha.9.png", "res/drawable-hdpi-v4/abc_popup_background_mtrl_mult.9.png", "res/drawable-hdpi-v4/abc_ic_star_black_36dp.png", "res/drawable-hdpi-v4/abc_list_selector_disabled_holo_dark.9.png", "res/drawable-hdpi-v4/abc_spinner_mtrl_am_alpha.9.png", "res/drawable-hdpi-v4/abc_text_select_handle_left_mtrl_light.png", "res/drawable-hdpi-v4/abc_list_longpressed_holo.9.png", "res/drawable-hdpi-v4/abc_btn_check_to_on_mtrl_000.png", "res/drawable-hdpi-v4/abc_list_pressed_holo_dark.9.png", "res/drawable-hdpi-v4/abc_cab_background_top_mtrl_alpha.9.png", "res/drawable-hdpi-v4/abc_btn_check_to_on_mtrl_015.png", "res/drawable-hdpi-v4/abc_text_select_handle_left_mtrl_dark.png", "res/drawable-hdpi-v4/abc_text_select_handle_middle_mtrl_light.png", "res/drawable-hdpi-v4/abc_switch_track_mtrl_alpha.9.png", "res/drawable-hdpi-v4/abc_ic_menu_selectall_mtrl_alpha.png", "res/drawable-hdpi-v4/notification_bg_low_normal.9.png", "res/drawable-hdpi-v4/abc_btn_radio_to_on_mtrl_015.png", "res/drawable-hdpi-v4/abc_text_select_handle_middle_mtrl_dark.png", "res/drawable-hdpi-v4/abc_tab_indicator_mtrl_alpha.9.png", "res/drawable-hdpi-v4/abc_ic_star_black_48dp.png", "res/drawable-hdpi-v4/abc_ic_menu_copy_mtrl_am_alpha.png", "res/drawable-hdpi-v4/abc_list_divider_mtrl_alpha.9.png", "res/drawable-hdpi-v4/abc_textfield_search_activated_mtrl_alpha.9.png", "res/drawable-hdpi-v4/abc_text_select_handle_right_mtrl_dark.png", "res/drawable-hdpi-v4/abc_scrubber_track_mtrl_alpha.9.png", "res/drawable-hdpi-v4/abc_scrubber_primary_mtrl_alpha.9.png", "res/drawable-hdpi-v4/abc_scrubber_control_to_pressed_mtrl_000.png", "res/drawable-hdpi-v4/abc_ic_star_half_black_16dp.png", "res/drawable-hdpi-v4/abc_scrubber_control_to_pressed_mtrl_005.png", "res/drawable-hdpi-v4/notification_bg_normal.9.png", "res/drawable-hdpi-v4/abc_ic_star_half_black_36dp.png", "res/drawable-hdpi-v4/notify_panel_notification_icon_bg.png", "res/drawable-hdpi-v4/abc_textfield_search_default_mtrl_alpha.9.png", "res/drawable-hdpi-v4/abc_text_select_handle_right_mtrl_light.png", "res/drawable-hdpi-v4/notification_bg_low_pressed.9.png", "res/drawable-hdpi-v4/abc_textfield_default_mtrl_alpha.9.png", "res/drawable-hdpi-v4/notification_bg_normal_pressed.9.png", "res/drawable-hdpi-v4/abc_ic_menu_paste_mtrl_am_alpha.png", "res/drawable-hdpi-v4/abc_btn_switch_to_on_mtrl_00001.9.png", "res/drawable-hdpi-v4/abc_ic_star_black_16dp.png", "res/drawable-hdpi-v4/abc_list_selector_disabled_holo_light.9.png", "res/drawable-hdpi-v4/abc_ic_commit_search_api_mtrl_alpha.png", "res/drawable-hdpi-v4/abc_ab_share_pack_mtrl_alpha.9.png", "res/drawable-hdpi-v4/abc_btn_radio_to_on_mtrl_000.png", "res/drawable-hdpi-v4/abc_ic_star_half_black_48dp.png", "res/drawable-hdpi-v4/abc_ic_menu_cut_mtrl_alpha.png", "res/values-v22/values-v22.xml", "res/values-bn-rBD/values-bn-rBD.xml", "res/values-v24/values-v24.xml", "res/values-is-rIS/values-is-rIS.xml", "res/values-gu-rIN/values-gu-rIN.xml", "res/drawable-mdpi-v4/abc_ic_menu_share_mtrl_alpha.png", "res/drawable-mdpi-v4/abc_list_pressed_holo_light.9.png", "res/drawable-mdpi-v4/abc_btn_switch_to_on_mtrl_00012.9.png", "res/drawable-mdpi-v4/abc_scrubber_control_off_mtrl_alpha.png", "res/drawable-mdpi-v4/abc_list_focused_holo.9.png", "res/drawable-mdpi-v4/abc_menu_hardkey_panel_mtrl_mult.9.png", "res/drawable-mdpi-v4/abc_textfield_activated_mtrl_alpha.9.png", "res/drawable-mdpi-v4/abc_popup_background_mtrl_mult.9.png", "res/drawable-mdpi-v4/abc_ic_star_black_36dp.png", "res/drawable-mdpi-v4/abc_list_selector_disabled_holo_dark.9.png", "res/drawable-mdpi-v4/abc_spinner_mtrl_am_alpha.9.png", "res/drawable-mdpi-v4/abc_text_select_handle_left_mtrl_light.png", "res/drawable-mdpi-v4/abc_list_longpressed_holo.9.png", "res/drawable-mdpi-v4/abc_btn_check_to_on_mtrl_000.png", "res/drawable-mdpi-v4/abc_list_pressed_holo_dark.9.png", "res/drawable-mdpi-v4/abc_cab_background_top_mtrl_alpha.9.png", "res/drawable-mdpi-v4/abc_btn_check_to_on_mtrl_015.png", "res/drawable-mdpi-v4/abc_text_select_handle_left_mtrl_dark.png", "res/drawable-mdpi-v4/abc_text_select_handle_middle_mtrl_light.png", "res/drawable-mdpi-v4/abc_switch_track_mtrl_alpha.9.png", "res/drawable-mdpi-v4/abc_ic_menu_selectall_mtrl_alpha.png", "res/drawable-mdpi-v4/notification_bg_low_normal.9.png", "res/drawable-mdpi-v4/abc_btn_radio_to_on_mtrl_015.png", "res/drawable-mdpi-v4/abc_text_select_handle_middle_mtrl_dark.png", "res/drawable-mdpi-v4/abc_tab_indicator_mtrl_alpha.9.png", "res/drawable-mdpi-v4/abc_ic_star_black_48dp.png", "res/drawable-mdpi-v4/abc_ic_menu_copy_mtrl_am_alpha.png", "res/drawable-mdpi-v4/abc_list_divider_mtrl_alpha.9.png", "res/drawable-mdpi-v4/abc_textfield_search_activated_mtrl_alpha.9.png", "res/drawable-mdpi-v4/abc_text_select_handle_right_mtrl_dark.png", "res/drawable-mdpi-v4/abc_scrubber_track_mtrl_alpha.9.png", "res/drawable-mdpi-v4/abc_scrubber_primary_mtrl_alpha.9.png", "res/drawable-mdpi-v4/abc_scrubber_control_to_pressed_mtrl_000.png", "res/drawable-mdpi-v4/abc_ic_star_half_black_16dp.png", "res/drawable-mdpi-v4/abc_scrubber_control_to_pressed_mtrl_005.png", "res/drawable-mdpi-v4/notification_bg_normal.9.png", "res/drawable-mdpi-v4/abc_ic_star_half_black_36dp.png", "res/drawable-mdpi-v4/notify_panel_notification_icon_bg.png", "res/drawable-mdpi-v4/abc_textfield_search_default_mtrl_alpha.9.png", "res/drawable-mdpi-v4/abc_text_select_handle_right_mtrl_light.png", "res/drawable-mdpi-v4/notification_bg_low_pressed.9.png", "res/drawable-mdpi-v4/abc_textfield_default_mtrl_alpha.9.png", "res/drawable-mdpi-v4/notification_bg_normal_pressed.9.png", "res/drawable-mdpi-v4/abc_ic_menu_paste_mtrl_am_alpha.png", "res/drawable-mdpi-v4/abc_btn_switch_to_on_mtrl_00001.9.png", "res/drawable-mdpi-v4/abc_ic_star_black_16dp.png", "res/drawable-mdpi-v4/abc_list_selector_disabled_holo_light.9.png", "res/drawable-mdpi-v4/abc_ic_commit_search_api_mtrl_alpha.png", "res/drawable-mdpi-v4/abc_ab_share_pack_mtrl_alpha.9.png", "res/drawable-mdpi-v4/abc_btn_radio_to_on_mtrl_000.png", "res/drawable-mdpi-v4/abc_ic_star_half_black_48dp.png", "res/drawable-mdpi-v4/abc_ic_menu_cut_mtrl_alpha.png", "res/values-pa-rIN/values-pa-rIN.xml", "res/values-mr-rIN/values-mr-rIN.xml", "res/values-ru/values-ru.xml", "res/values-pl/values-pl.xml", "res/values-fa/values-fa.xml", "res/values-v11/values-v11.xml", "res/values-be-rBY/values-be-rBY.xml", "res/values-si-rLK/values-si-rLK.xml", "res/values-sv/values-sv.xml", "res/anim/abc_popup_exit.xml", "res/anim/abc_slide_out_top.xml", "res/anim/abc_grow_fade_in_from_bottom.xml", "res/anim/abc_popup_enter.xml", "res/anim/abc_slide_in_bottom.xml", "res/anim/abc_shrink_fade_out_from_bottom.xml", "res/anim/abc_slide_in_top.xml", "res/anim/abc_fade_out.xml", "res/anim/abc_slide_out_bottom.xml", "res/anim/abc_fade_in.xml", "res/values-my-rMM/values-my-rMM.xml", "res/values-b+sr+Latn/values-b+sr+Latn.xml", "res/values-fr/values-fr.xml", "res/values-uz-rUZ/values-uz-rUZ.xml", "res/values-ms-rMY/values-ms-rMY.xml", "res/values-ka-rGE/values-ka-rGE.xml", "res/values-fi/values-fi.xml", "res/values-fr-rCA/values-fr-rCA.xml", "res/values-v17/values-v17.xml", "res/values-ca/values-ca.xml", "res/values-in/values-in.xml", "res/values-vi/values-vi.xml", "res/drawable-ldrtl-hdpi-v17/abc_spinner_mtrl_am_alpha.9.png", "res/drawable-ldrtl-hdpi-v17/abc_ic_menu_copy_mtrl_am_alpha.png", "res/drawable-ldrtl-hdpi-v17/abc_ic_menu_cut_mtrl_alpha.png", "res/layout/notification_media_cancel_action.xml", "res/layout/select_dialog_item_material.xml", "res/layout/notification_template_custom_big.xml", "res/layout/abc_action_bar_up_container.xml", "res/layout/abc_dialog_title_material.xml", "res/layout/notification_template_big_media_narrow.xml", "res/layout/abc_select_dialog_material.xml", "res/layout/abc_list_menu_item_layout.xml", "res/layout/notification_template_part_chronometer.xml", "res/layout/abc_popup_menu_header_item_layout.xml", "res/layout/notification_template_lines_media.xml", "res/layout/notification_template_part_time.xml", "res/layout/abc_list_menu_item_icon.xml", "res/layout/notification_action_tombstone.xml", "res/layout/abc_action_mode_bar.xml", "res/layout/notification_template_media_custom.xml", "res/layout/abc_popup_menu_item_layout.xml", "res/layout/abc_action_menu_item_layout.xml", "res/layout/abc_activity_chooser_view_list_item.xml", "res/layout/abc_list_menu_item_radio.xml", "res/layout/abc_screen_content_include.xml", "res/layout/abc_activity_chooser_view.xml", "res/layout/abc_alert_dialog_button_bar_material.xml", "res/layout/abc_action_menu_layout.xml", "res/layout/notification_template_big_media_narrow_custom.xml", "res/layout/notification_template_big_media_custom.xml", "res/layout/abc_list_menu_item_checkbox.xml", "res/layout/notification_media_action.xml", "res/layout/notification_template_icon_group.xml", "res/layout/abc_screen_simple.xml", "res/layout/abc_screen_simple_overlay_action_mode.xml", "res/layout/abc_screen_toolbar.xml", "res/layout/abc_alert_dialog_material.xml", "res/layout/abc_expanded_menu_layout.xml", "res/layout/abc_search_view.xml", "res/layout/notification_template_big_media.xml", "res/layout/abc_search_dropdown_item_icons_2line.xml", "res/layout/abc_action_bar_view_list_nav_layout.xml", "res/layout/select_dialog_multichoice_material.xml", "res/layout/abc_action_mode_close_item_material.xml", "res/layout/notification_template_media.xml", "res/layout/support_simple_spinner_dropdown_item.xml", "res/layout/notification_action.xml", "res/layout/abc_action_bar_title_item.xml", "res/layout/select_dialog_singlechoice_material.xml", "res/values-en-rGB/values-en-rGB.xml", "res/values-ja/values-ja.xml", "res/values-zh-rCN/values-zh-rCN.xml", "res/values-am/values-am.xml", "res/values-sq-rAL/values-sq-rAL.xml", "res/values-v16/values-v16.xml", "res/values-sl/values-sl.xml", "res/values-de/values-de.xml", "res/values-kk-rKZ/values-kk-rKZ.xml", "res/drawable-xxxhdpi-v4/abc_ic_menu_share_mtrl_alpha.png", "res/drawable-xxxhdpi-v4/abc_btn_switch_to_on_mtrl_00012.9.png", "res/drawable-xxxhdpi-v4/abc_ic_star_black_36dp.png", "res/drawable-xxxhdpi-v4/abc_spinner_mtrl_am_alpha.9.png", "res/drawable-xxxhdpi-v4/abc_text_select_handle_left_mtrl_light.png", "res/drawable-xxxhdpi-v4/abc_btn_check_to_on_mtrl_000.png", "res/drawable-xxxhdpi-v4/abc_btn_check_to_on_mtrl_015.png", "res/drawable-xxxhdpi-v4/abc_text_select_handle_left_mtrl_dark.png", "res/drawable-xxxhdpi-v4/abc_switch_track_mtrl_alpha.9.png", "res/drawable-xxxhdpi-v4/abc_ic_menu_selectall_mtrl_alpha.png", "res/drawable-xxxhdpi-v4/abc_btn_radio_to_on_mtrl_015.png", "res/drawable-xxxhdpi-v4/abc_tab_indicator_mtrl_alpha.9.png", "res/drawable-xxxhdpi-v4/abc_ic_star_black_48dp.png", "res/drawable-xxxhdpi-v4/abc_ic_menu_copy_mtrl_am_alpha.png", "res/drawable-xxxhdpi-v4/abc_text_select_handle_right_mtrl_dark.png", "res/drawable-xxxhdpi-v4/abc_scrubber_control_to_pressed_mtrl_000.png", "res/drawable-xxxhdpi-v4/abc_ic_star_half_black_16dp.png", "res/drawable-xxxhdpi-v4/abc_scrubber_control_to_pressed_mtrl_005.png", "res/drawable-xxxhdpi-v4/abc_ic_star_half_black_36dp.png", "res/drawable-xxxhdpi-v4/abc_text_select_handle_right_mtrl_light.png", "res/drawable-xxxhdpi-v4/abc_ic_menu_paste_mtrl_am_alpha.png", "res/drawable-xxxhdpi-v4/abc_btn_switch_to_on_mtrl_00001.9.png", "res/drawable-xxxhdpi-v4/abc_ic_star_black_16dp.png", "res/drawable-xxxhdpi-v4/abc_btn_radio_to_on_mtrl_000.png", "res/drawable-xxxhdpi-v4/abc_ic_star_half_black_48dp.png", "res/drawable-xxxhdpi-v4/abc_ic_menu_cut_mtrl_alpha.png", "res/values-en-rAU/values-en-rAU.xml", "res/values-en-rIN/values-en-rIN.xml", "res/values-zh-rTW/values-zh-rTW.xml", "res/values-sw/values-sw.xml", "res/values-nb/values-nb.xml", "res/values-h720dp-v13/values-h720dp-v13.xml", "res/values-bs-rBA/values-bs-rBA.xml", "res/values-tr/values-tr.xml", "res/drawable-ldrtl-mdpi-v17/abc_spinner_mtrl_am_alpha.9.png", "res/drawable-ldrtl-mdpi-v17/abc_ic_menu_copy_mtrl_am_alpha.png", "res/drawable-ldrtl-mdpi-v17/abc_ic_menu_cut_mtrl_alpha.png", "res/drawable-v23/abc_control_background_material.xml", "res/values-kn-rIN/values-kn-rIN.xml", "res/values-hy-rAM/values-hy-rAM.xml", "res/values-sw600dp-v13/values-sw600dp-v13.xml", "res/values-es-rUS/values-es-rUS.xml", "res/values-land/values-land.xml", "res/values-zh-rHK/values-zh-rHK.xml", "res/drawable-ldrtl-xxhdpi-v17/abc_spinner_mtrl_am_alpha.9.png", "res/drawable-ldrtl-xxhdpi-v17/abc_ic_menu_copy_mtrl_am_alpha.png", "res/drawable-ldrtl-xxhdpi-v17/abc_ic_menu_cut_mtrl_alpha.png", "res/values-large-v4/values-large-v4.xml", "res/values-ko/values-ko.xml", "res/values-pt-rPT/values-pt-rPT.xml", "res/values-iw/values-iw.xml", "res/values-lt/values-lt.xml", "res/values-ro/values-ro.xml", "res/values-v14/values-v14.xml", "res/values-pt/values-pt.xml", "res/layout-v16/notification_template_custom_big.xml", "res/values-ar/values-ar.xml", "res/color-v23/abc_tint_seek_thumb.xml", "res/color-v23/abc_tint_btn_checkable.xml", "res/color-v23/abc_tint_edittext.xml", "res/color-v23/abc_tint_switch_thumb.xml", "res/color-v23/abc_btn_colored_borderless_text_material.xml", "res/color-v23/abc_tint_default.xml", "res/color-v23/abc_color_highlight_material.xml", "res/color-v23/abc_tint_spinner.xml", "res/color-v23/abc_tint_switch_track.xml", "res/values-hdpi-v4/values-hdpi-v4.xml", "res/values-ur-rPK/values-ur-rPK.xml", "res/values-ml-rIN/values-ml-rIN.xml", "res/drawable-xhdpi-v4/abc_ic_menu_share_mtrl_alpha.png", "res/drawable-xhdpi-v4/abc_list_pressed_holo_light.9.png", "res/drawable-xhdpi-v4/abc_btn_switch_to_on_mtrl_00012.9.png", "res/drawable-xhdpi-v4/abc_scrubber_control_off_mtrl_alpha.png", "res/drawable-xhdpi-v4/abc_list_focused_holo.9.png", "res/drawable-xhdpi-v4/abc_menu_hardkey_panel_mtrl_mult.9.png", "res/drawable-xhdpi-v4/abc_textfield_activated_mtrl_alpha.9.png", "res/drawable-xhdpi-v4/abc_popup_background_mtrl_mult.9.png", "res/drawable-xhdpi-v4/abc_ic_star_black_36dp.png", "res/drawable-xhdpi-v4/abc_list_selector_disabled_holo_dark.9.png", "res/drawable-xhdpi-v4/abc_spinner_mtrl_am_alpha.9.png", "res/drawable-xhdpi-v4/abc_text_select_handle_left_mtrl_light.png", "res/drawable-xhdpi-v4/abc_list_longpressed_holo.9.png", "res/drawable-xhdpi-v4/abc_btn_check_to_on_mtrl_000.png", "res/drawable-xhdpi-v4/abc_list_pressed_holo_dark.9.png", "res/drawable-xhdpi-v4/abc_cab_background_top_mtrl_alpha.9.png", "res/drawable-xhdpi-v4/abc_btn_check_to_on_mtrl_015.png", "res/drawable-xhdpi-v4/abc_text_select_handle_left_mtrl_dark.png", "res/drawable-xhdpi-v4/abc_text_select_handle_middle_mtrl_light.png", "res/drawable-xhdpi-v4/abc_switch_track_mtrl_alpha.9.png", "res/drawable-xhdpi-v4/abc_ic_menu_selectall_mtrl_alpha.png", "res/drawable-xhdpi-v4/notification_bg_low_normal.9.png", "res/drawable-xhdpi-v4/abc_btn_radio_to_on_mtrl_015.png", "res/drawable-xhdpi-v4/abc_text_select_handle_middle_mtrl_dark.png", "res/drawable-xhdpi-v4/abc_tab_indicator_mtrl_alpha.9.png", "res/drawable-xhdpi-v4/abc_ic_star_black_48dp.png", "res/drawable-xhdpi-v4/abc_ic_menu_copy_mtrl_am_alpha.png", "res/drawable-xhdpi-v4/abc_list_divider_mtrl_alpha.9.png", "res/drawable-xhdpi-v4/abc_textfield_search_activated_mtrl_alpha.9.png", "res/drawable-xhdpi-v4/abc_text_select_handle_right_mtrl_dark.png", "res/drawable-xhdpi-v4/abc_scrubber_track_mtrl_alpha.9.png", "res/drawable-xhdpi-v4/abc_scrubber_primary_mtrl_alpha.9.png", "res/drawable-xhdpi-v4/abc_scrubber_control_to_pressed_mtrl_000.png", "res/drawable-xhdpi-v4/abc_ic_star_half_black_16dp.png", "res/drawable-xhdpi-v4/abc_scrubber_control_to_pressed_mtrl_005.png", "res/drawable-xhdpi-v4/notification_bg_normal.9.png", "res/drawable-xhdpi-v4/abc_ic_star_half_black_36dp.png", "res/drawable-xhdpi-v4/notify_panel_notification_icon_bg.png", "res/drawable-xhdpi-v4/abc_textfield_search_default_mtrl_alpha.9.png", "res/drawable-xhdpi-v4/abc_text_select_handle_right_mtrl_light.png", "res/drawable-xhdpi-v4/notification_bg_low_pressed.9.png", "res/drawable-xhdpi-v4/abc_textfield_default_mtrl_alpha.9.png", "res/drawable-xhdpi-v4/notification_bg_normal_pressed.9.png", "res/drawable-xhdpi-v4/abc_ic_menu_paste_mtrl_am_alpha.png", "res/drawable-xhdpi-v4/abc_btn_switch_to_on_mtrl_00001.9.png", "res/drawable-xhdpi-v4/abc_ic_star_black_16dp.png", "res/drawable-xhdpi-v4/abc_list_selector_disabled_holo_light.9.png", "res/drawable-xhdpi-v4/abc_ic_commit_search_api_mtrl_alpha.png", "res/drawable-xhdpi-v4/abc_ab_share_pack_mtrl_alpha.9.png", "res/drawable-xhdpi-v4/abc_btn_radio_to_on_mtrl_000.png", "res/drawable-xhdpi-v4/abc_ic_star_half_black_48dp.png", "res/drawable-xhdpi-v4/abc_ic_menu_cut_mtrl_alpha.png", "res/values/values.xml", "res/values-hr/values-hr.xml", "res/values-mn-rMN/values-mn-rMN.xml", "res/values-da/values-da.xml", "res/values-hi/values-hi.xml", "res/values-it/values-it.xml", "res/color-v11/abc_background_cache_hint_selector_material_light.xml", "res/color-v11/abc_background_cache_hint_selector_material_dark.xml", "res/values-night-v8/values-night-v8.xml", "res/values-es/values-es.xml", "res/values-sk/values-sk.xml", "res/layout-v21/notification_template_custom_big.xml", "res/layout-v21/notification_action_tombstone.xml", "res/layout-v21/notification_template_icon_group.xml", "res/layout-v21/notification_action.xml", "res/values-lv/values-lv.xml", "res/values-ky-rKG/values-ky-rKG.xml", "res/values-v25/values-v25.xml", "res/values-hu/values-hu.xml", "res/drawable-xxhdpi-v4/abc_ic_menu_share_mtrl_alpha.png", "res/drawable-xxhdpi-v4/abc_list_pressed_holo_light.9.png", "res/drawable-xxhdpi-v4/abc_btn_switch_to_on_mtrl_00012.9.png", "res/drawable-xxhdpi-v4/abc_scrubber_control_off_mtrl_alpha.png", "res/drawable-xxhdpi-v4/abc_list_focused_holo.9.png", "res/drawable-xxhdpi-v4/abc_menu_hardkey_panel_mtrl_mult.9.png", "res/drawable-xxhdpi-v4/abc_textfield_activated_mtrl_alpha.9.png", "res/drawable-xxhdpi-v4/abc_popup_background_mtrl_mult.9.png", "res/drawable-xxhdpi-v4/abc_ic_star_black_36dp.png", "res/drawable-xxhdpi-v4/abc_list_selector_disabled_holo_dark.9.png", "res/drawable-xxhdpi-v4/abc_spinner_mtrl_am_alpha.9.png", "res/drawable-xxhdpi-v4/abc_text_select_handle_left_mtrl_light.png", "res/drawable-xxhdpi-v4/abc_list_longpressed_holo.9.png", "res/drawable-xxhdpi-v4/abc_btn_check_to_on_mtrl_000.png", "res/drawable-xxhdpi-v4/abc_list_pressed_holo_dark.9.png", "res/drawable-xxhdpi-v4/abc_cab_background_top_mtrl_alpha.9.png", "res/drawable-xxhdpi-v4/abc_btn_check_to_on_mtrl_015.png", "res/drawable-xxhdpi-v4/abc_text_select_handle_left_mtrl_dark.png", "res/drawable-xxhdpi-v4/abc_text_select_handle_middle_mtrl_light.png", "res/drawable-xxhdpi-v4/abc_switch_track_mtrl_alpha.9.png", "res/drawable-xxhdpi-v4/abc_ic_menu_selectall_mtrl_alpha.png", "res/drawable-xxhdpi-v4/abc_btn_radio_to_on_mtrl_015.png", "res/drawable-xxhdpi-v4/abc_text_select_handle_middle_mtrl_dark.png", "res/drawable-xxhdpi-v4/abc_tab_indicator_mtrl_alpha.9.png", "res/drawable-xxhdpi-v4/abc_ic_star_black_48dp.png", "res/drawable-xxhdpi-v4/abc_ic_menu_copy_mtrl_am_alpha.png", "res/drawable-xxhdpi-v4/abc_list_divider_mtrl_alpha.9.png", "res/drawable-xxhdpi-v4/abc_textfield_search_activated_mtrl_alpha.9.png", "res/drawable-xxhdpi-v4/abc_text_select_handle_right_mtrl_dark.png", "res/drawable-xxhdpi-v4/abc_scrubber_track_mtrl_alpha.9.png", "res/drawable-xxhdpi-v4/abc_scrubber_primary_mtrl_alpha.9.png", "res/drawable-xxhdpi-v4/abc_scrubber_control_to_pressed_mtrl_000.png", "res/drawable-xxhdpi-v4/abc_ic_star_half_black_16dp.png", "res/drawable-xxhdpi-v4/abc_scrubber_control_to_pressed_mtrl_005.png", "res/drawable-xxhdpi-v4/abc_ic_star_half_black_36dp.png", "res/drawable-xxhdpi-v4/abc_textfield_search_default_mtrl_alpha.9.png", "res/drawable-xxhdpi-v4/abc_text_select_handle_right_mtrl_light.png", "res/drawable-xxhdpi-v4/abc_textfield_default_mtrl_alpha.9.png", "res/drawable-xxhdpi-v4/abc_ic_menu_paste_mtrl_am_alpha.png", "res/drawable-xxhdpi-v4/abc_btn_switch_to_on_mtrl_00001.9.png", "res/drawable-xxhdpi-v4/abc_ic_star_black_16dp.png", "res/drawable-xxhdpi-v4/abc_list_selector_disabled_holo_light.9.png", "res/drawable-xxhdpi-v4/abc_ic_commit_search_api_mtrl_alpha.png", "res/drawable-xxhdpi-v4/abc_ab_share_pack_mtrl_alpha.9.png", "res/drawable-xxhdpi-v4/abc_btn_radio_to_on_mtrl_000.png", "res/drawable-xxhdpi-v4/abc_ic_star_half_black_48dp.png", "res/drawable-xxhdpi-v4/abc_ic_menu_cut_mtrl_alpha.png", "res/color/abc_search_url_text.xml", "res/color/switch_thumb_material_dark.xml", "res/color/abc_hint_foreground_material_light.xml", "res/color/abc_secondary_text_material_dark.xml", "res/color/abc_tint_seek_thumb.xml", "res/color/abc_tint_btn_checkable.xml", "res/color/abc_tint_edittext.xml", "res/color/abc_hint_foreground_material_dark.xml", "res/color/switch_thumb_material_light.xml", "res/color/abc_tint_switch_thumb.xml", "res/color/abc_btn_colored_borderless_text_material.xml", "res/color/abc_primary_text_material_light.xml", "res/color/abc_background_cache_hint_selector_material_light.xml", "res/color/abc_secondary_text_material_light.xml", "res/color/abc_primary_text_disable_only_material_light.xml", "res/color/abc_primary_text_disable_only_material_dark.xml", "res/color/abc_tint_default.xml", "res/color/abc_tint_spinner.xml", "res/color/abc_tint_switch_track.xml", "res/color/abc_background_cache_hint_selector_material_dark.xml", "res/color/abc_primary_text_material_dark.xml", "res/values-v12/values-v12.xml", "res/values-th/values-th.xml", "res/values-cs/values-cs.xml", "res/values-sr/values-sr.xml", "res/values-v13/values-v13.xml", "res/values-tl/values-tl.xml", "res/values-te-rIN/values-te-rIN.xml", "res/values-ne-rNP/values-ne-rNP.xml", "res/values-ta-rIN/values-ta-rIN.xml", "res/values-ldltr-v21/values-ldltr-v21.xml", "res/drawable/abc_switch_thumb_material.xml", "res/drawable/abc_btn_borderless_material.xml", "res/drawable/abc_textfield_search_material.xml", "res/drawable/abc_seekbar_track_material.xml", "res/drawable/abc_btn_colored_material.xml", "res/drawable/abc_ratingbar_indicator_material.xml", "res/drawable/notification_tile_bg.xml", "res/drawable/abc_ic_ab_back_material.xml", "res/drawable/notification_icon_background.xml", "res/drawable/notification_bg_low.xml", "res/drawable/abc_btn_default_mtrl_shape.xml", "res/drawable/abc_seekbar_thumb_material.xml", "res/drawable/abc_cab_background_internal_bg.xml", "res/drawable/abc_dialog_material_background.xml", "res/drawable/abc_text_cursor_material.xml", "res/drawable/notification_bg.xml", "res/drawable/abc_btn_radio_material.xml", "res/drawable/abc_item_background_holo_dark.xml", "res/drawable/abc_list_selector_holo_light.xml", "res/drawable/abc_ic_voice_search_api_material.xml", "res/drawable/abc_ic_search_api_material.xml", "res/drawable/abc_cab_background_top_material.xml", "res/drawable/abc_list_selector_background_transition_holo_dark.xml", "res/drawable/abc_edit_text_material.xml", "res/drawable/abc_tab_indicator_material.xml", "res/drawable/abc_ratingbar_material.xml", "res/drawable/abc_seekbar_tick_mark_material.xml", "res/drawable/abc_ic_go_search_api_material.xml", "res/drawable/abc_list_selector_holo_dark.xml", "res/drawable/abc_ic_arrow_drop_right_black_24dp.xml", "res/drawable/abc_btn_check_material.xml", "res/drawable/abc_spinner_textfield_background_material.xml", "res/drawable/abc_ic_clear_material.xml", "res/drawable/abc_item_background_holo_light.xml", "res/drawable/abc_list_selector_background_transition_holo_light.xml", "res/drawable/abc_ic_menu_overflow_material.xml", "res/drawable/abc_vector_test.xml", "res/drawable/abc_ratingbar_small_material.xml" ]
+subjar_tuples = [  ]
+subjars = [  ]
diff --git a/build/secondary/third_party/android_tools/support/android_support_v7_gridlayout_java.info b/build/secondary/third_party/android_tools/support/android_support_v7_gridlayout_java.info
new file mode 100644
index 0000000..28c8330
--- /dev/null
+++ b/build/secondary/third_party/android_tools/support/android_support_v7_gridlayout_java.info
@@ -0,0 +1,13 @@
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+aidl = [  ]
+assets = [  ]
+has_classes_jar = true
+has_native_libraries = false
+has_proguard_flags = false
+has_r_text_file = true
+is_manifest_empty = true
+resources = [ "res/values/values.xml" ]
+subjar_tuples = [  ]
+subjars = [  ]
diff --git a/build/secondary/third_party/android_tools/support/android_support_v7_mediarouter_java.info b/build/secondary/third_party/android_tools/support/android_support_v7_mediarouter_java.info
new file mode 100644
index 0000000..55b51f5
--- /dev/null
+++ b/build/secondary/third_party/android_tools/support/android_support_v7_mediarouter_java.info
@@ -0,0 +1,13 @@
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+aidl = [  ]
+assets = [  ]
+has_classes_jar = true
+has_native_libraries = false
+has_proguard_flags = false
+has_r_text_file = true
+is_manifest_empty = true
+resources = [ "res/values-km-rKH/values-km-rKH.xml", "res/values-nl/values-nl.xml", "res/values-az-rAZ/values-az-rAZ.xml", "res/values-gl-rES/values-gl-rES.xml", "res/values-bg/values-bg.xml", "res/values-pt-rBR/values-pt-rBR.xml", "res/values-eu-rES/values-eu-rES.xml", "res/values-el/values-el.xml", "res/values-sw720dp-v13/values-sw720dp-v13.xml", "res/values-mk-rMK/values-mk-rMK.xml", "res/values-af/values-af.xml", "res/values-uk/values-uk.xml", "res/values-zu/values-zu.xml", "res/values-et-rEE/values-et-rEE.xml", "res/values-lo-rLA/values-lo-rLA.xml", "res/drawable-hdpi-v4/ic_mr_button_disconnected_light.png", "res/drawable-hdpi-v4/ic_vol_type_speaker_group_light.png", "res/drawable-hdpi-v4/ic_audiotrack_light.png", "res/drawable-hdpi-v4/ic_vol_type_speaker_light.png", "res/drawable-hdpi-v4/ic_vol_type_tv_dark.png", "res/drawable-hdpi-v4/ic_dialog_close_dark.png", "res/drawable-hdpi-v4/ic_vol_type_tv_light.png", "res/drawable-hdpi-v4/ic_mr_button_disabled_dark.png", "res/drawable-hdpi-v4/ic_mr_button_disabled_light.png", "res/drawable-hdpi-v4/ic_dialog_close_light.png", "res/drawable-hdpi-v4/ic_mr_button_disconnected_dark.png", "res/drawable-hdpi-v4/ic_vol_type_speaker_group_dark.png", "res/drawable-hdpi-v4/ic_vol_type_speaker_dark.png", "res/drawable-hdpi-v4/ic_media_pause_light.png", "res/drawable-hdpi-v4/ic_mr_button_grey.png", "res/drawable-hdpi-v4/ic_audiotrack_dark.png", "res/drawable-hdpi-v4/ic_media_play_light.png", "res/drawable-hdpi-v4/ic_media_pause_dark.png", "res/drawable-hdpi-v4/ic_media_play_dark.png", "res/values-bn-rBD/values-bn-rBD.xml", "res/values-is-rIS/values-is-rIS.xml", "res/values-gu-rIN/values-gu-rIN.xml", "res/drawable-mdpi-v4/ic_mr_button_disconnected_light.png", "res/drawable-mdpi-v4/ic_vol_type_speaker_group_light.png", "res/drawable-mdpi-v4/ic_audiotrack_light.png", "res/drawable-mdpi-v4/ic_vol_type_speaker_light.png", "res/drawable-mdpi-v4/ic_vol_type_tv_dark.png", "res/drawable-mdpi-v4/ic_dialog_close_dark.png", "res/drawable-mdpi-v4/ic_vol_type_tv_light.png", "res/drawable-mdpi-v4/ic_mr_button_disabled_dark.png", "res/drawable-mdpi-v4/ic_mr_button_disabled_light.png", "res/drawable-mdpi-v4/ic_dialog_close_light.png", "res/drawable-mdpi-v4/ic_mr_button_disconnected_dark.png", "res/drawable-mdpi-v4/ic_vol_type_speaker_group_dark.png", "res/drawable-mdpi-v4/ic_vol_type_speaker_dark.png", "res/drawable-mdpi-v4/ic_media_pause_light.png", "res/drawable-mdpi-v4/ic_mr_button_grey.png", "res/drawable-mdpi-v4/ic_audiotrack_dark.png", "res/drawable-mdpi-v4/ic_media_play_light.png", "res/drawable-mdpi-v4/ic_media_pause_dark.png", "res/drawable-mdpi-v4/ic_media_play_dark.png", "res/values-pa-rIN/values-pa-rIN.xml", "res/values-mr-rIN/values-mr-rIN.xml", "res/values-ru/values-ru.xml", "res/values-pl/values-pl.xml", "res/values-fa/values-fa.xml", "res/values-be-rBY/values-be-rBY.xml", "res/values-si-rLK/values-si-rLK.xml", "res/values-sv/values-sv.xml", "res/values-my-rMM/values-my-rMM.xml", "res/values-b+sr+Latn/values-b+sr+Latn.xml", "res/interpolator/mr_linear_out_slow_in.xml", "res/interpolator/mr_fast_out_slow_in.xml", "res/values-fr/values-fr.xml", "res/values-uz-rUZ/values-uz-rUZ.xml", "res/values-ms-rMY/values-ms-rMY.xml", "res/values-ka-rGE/values-ka-rGE.xml", "res/values-fi/values-fi.xml", "res/values-fr-rCA/values-fr-rCA.xml", "res/values-ca/values-ca.xml", "res/values-in/values-in.xml", "res/values-vi/values-vi.xml", "res/layout/mr_controller_material_dialog_b.xml", "res/layout/mr_chooser_dialog.xml", "res/layout/mr_chooser_list_item.xml", "res/layout/mr_volume_control.xml", "res/layout/mr_playback_control.xml", "res/layout/mr_controller_volume_item.xml", "res/values-en-rGB/values-en-rGB.xml", "res/values-ja/values-ja.xml", "res/values-zh-rCN/values-zh-rCN.xml", "res/values-am/values-am.xml", "res/values-sq-rAL/values-sq-rAL.xml", "res/values-sl/values-sl.xml", "res/values-de/values-de.xml", "res/values-kk-rKZ/values-kk-rKZ.xml", "res/drawable-xxxhdpi-v4/ic_group_collapse_03.png", "res/drawable-xxxhdpi-v4/ic_group_expand_15.png", "res/drawable-xxxhdpi-v4/ic_group_expand_13.png", "res/drawable-xxxhdpi-v4/ic_group_expand_10.png", "res/drawable-xxxhdpi-v4/ic_group_collapse_14.png", "res/drawable-xxxhdpi-v4/ic_group_expand_06.png", "res/drawable-xxxhdpi-v4/ic_group_collapse_11.png", "res/drawable-xxxhdpi-v4/ic_group_expand_11.png", "res/drawable-xxxhdpi-v4/ic_group_collapse_01.png", "res/drawable-xxxhdpi-v4/ic_group_collapse_10.png", "res/drawable-xxxhdpi-v4/ic_group_expand_07.png", "res/drawable-xxxhdpi-v4/ic_group_expand_09.png", "res/drawable-xxxhdpi-v4/ic_group_collapse_13.png", "res/drawable-xxxhdpi-v4/ic_group_expand_01.png", "res/drawable-xxxhdpi-v4/ic_group_collapse_00.png", "res/drawable-xxxhdpi-v4/ic_group_expand_00.png", "res/drawable-xxxhdpi-v4/ic_group_collapse_04.png", "res/drawable-xxxhdpi-v4/ic_group_expand_12.png", "res/drawable-xxxhdpi-v4/ic_group_expand_08.png", "res/drawable-xxxhdpi-v4/ic_group_expand_04.png", "res/drawable-xxxhdpi-v4/ic_group_collapse_08.png", "res/drawable-xxxhdpi-v4/ic_group_expand_03.png", "res/drawable-xxxhdpi-v4/ic_group_expand_02.png", "res/drawable-xxxhdpi-v4/ic_group_expand_05.png", "res/drawable-xxxhdpi-v4/ic_group_collapse_02.png", "res/drawable-xxxhdpi-v4/ic_group_collapse_07.png", "res/drawable-xxxhdpi-v4/ic_mr_button_grey.png", "res/drawable-xxxhdpi-v4/ic_group_collapse_05.png", "res/drawable-xxxhdpi-v4/ic_group_expand_14.png", "res/drawable-xxxhdpi-v4/ic_group_collapse_12.png", "res/drawable-xxxhdpi-v4/ic_group_collapse_06.png", "res/drawable-xxxhdpi-v4/ic_group_collapse_09.png", "res/drawable-xxxhdpi-v4/ic_group_collapse_15.png", "res/values-en-rAU/values-en-rAU.xml", "res/values-en-rIN/values-en-rIN.xml", "res/values-zh-rTW/values-zh-rTW.xml", "res/values-sw/values-sw.xml", "res/values-nb/values-nb.xml", "res/values-bs-rBA/values-bs-rBA.xml", "res/values-tr/values-tr.xml", "res/values-kn-rIN/values-kn-rIN.xml", "res/values-hy-rAM/values-hy-rAM.xml", "res/values-sw600dp-v13/values-sw600dp-v13.xml", "res/values-es-rUS/values-es-rUS.xml", "res/values-land/values-land.xml", "res/values-zh-rHK/values-zh-rHK.xml", "res/values-ko/values-ko.xml", "res/values-pt-rPT/values-pt-rPT.xml", "res/values-iw/values-iw.xml", "res/values-lt/values-lt.xml", "res/values-ro/values-ro.xml", "res/values-pt/values-pt.xml", "res/values-ar/values-ar.xml", "res/values-ur-rPK/values-ur-rPK.xml", "res/values-ml-rIN/values-ml-rIN.xml", "res/drawable-xhdpi-v4/ic_mr_button_connected_20_light.png", "res/drawable-xhdpi-v4/ic_mr_button_disconnected_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_06_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_14_dark.png", "res/drawable-xhdpi-v4/ic_vol_type_speaker_group_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_18_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_12_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_15_dark.png", "res/drawable-xhdpi-v4/ic_audiotrack_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_01_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_18_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_04_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_04_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_09_dark.png", "res/drawable-xhdpi-v4/ic_vol_type_speaker_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_03_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_19_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_15_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_17_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_20_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_07_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_12_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_19_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_11_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_22_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_10_light.png", "res/drawable-xhdpi-v4/ic_vol_type_tv_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_13_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_16_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_08_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_07_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_05_light.png", "res/drawable-xhdpi-v4/ic_dialog_close_dark.png", "res/drawable-xhdpi-v4/ic_vol_type_tv_light.png", "res/drawable-xhdpi-v4/ic_mr_button_disabled_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_disabled_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_13_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_00_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_09_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_02_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_02_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_21_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_21_light.png", "res/drawable-xhdpi-v4/ic_dialog_close_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_15_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_13_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_07_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_17_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_21_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_01_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_19_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_02_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_02_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_09_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_18_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_05_light.png", "res/drawable-xhdpi-v4/ic_mr_button_disconnected_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_10_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_14_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_00_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_03_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_15_light.png", "res/drawable-xhdpi-v4/ic_vol_type_speaker_group_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_06_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_11_light.png", "res/drawable-xhdpi-v4/ic_vol_type_speaker_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_10_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_16_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_08_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_09_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_11_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_05_dark.png", "res/drawable-xhdpi-v4/ic_media_pause_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_10_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_22_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_17_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_grey.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_08_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_04_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_16_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_20_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_03_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_14_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_17_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_06_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_06_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_20_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_01_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_16_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_21_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_12_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_12_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_22_light.png", "res/drawable-xhdpi-v4/ic_audiotrack_dark.png", "res/drawable-xhdpi-v4/ic_media_play_light.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_19_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_05_dark.png", "res/drawable-xhdpi-v4/ic_media_pause_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_22_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_14_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_11_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_00_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_08_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_13_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_18_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connecting_04_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_07_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_00_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_01_light.png", "res/drawable-xhdpi-v4/ic_media_play_dark.png", "res/drawable-xhdpi-v4/ic_mr_button_connected_03_light.png", "res/values/values.xml", "res/values-hr/values-hr.xml", "res/values-mn-rMN/values-mn-rMN.xml", "res/values-da/values-da.xml", "res/values-hi/values-hi.xml", "res/values-it/values-it.xml", "res/values-es/values-es.xml", "res/values-sk/values-sk.xml", "res/values-lv/values-lv.xml", "res/values-ky-rKG/values-ky-rKG.xml", "res/values-hu/values-hu.xml", "res/drawable-xxhdpi-v4/ic_mr_button_connected_20_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_disconnected_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_06_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_14_dark.png", "res/drawable-xxhdpi-v4/ic_vol_type_speaker_group_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_18_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_12_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_15_dark.png", "res/drawable-xxhdpi-v4/ic_audiotrack_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_01_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_18_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_04_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_04_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_09_dark.png", "res/drawable-xxhdpi-v4/ic_vol_type_speaker_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_03_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_19_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_15_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_17_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_20_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_07_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_12_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_19_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_11_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_22_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_10_light.png", "res/drawable-xxhdpi-v4/ic_vol_type_tv_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_13_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_16_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_08_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_07_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_05_light.png", "res/drawable-xxhdpi-v4/ic_dialog_close_dark.png", "res/drawable-xxhdpi-v4/ic_vol_type_tv_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_disabled_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_disabled_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_13_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_00_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_09_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_02_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_02_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_21_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_21_light.png", "res/drawable-xxhdpi-v4/ic_dialog_close_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_15_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_13_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_07_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_17_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_21_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_01_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_19_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_02_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_02_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_09_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_18_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_05_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_disconnected_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_10_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_14_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_00_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_03_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_15_light.png", "res/drawable-xxhdpi-v4/ic_vol_type_speaker_group_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_06_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_11_light.png", "res/drawable-xxhdpi-v4/ic_vol_type_speaker_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_10_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_16_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_08_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_09_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_11_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_05_dark.png", "res/drawable-xxhdpi-v4/ic_media_pause_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_10_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_22_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_17_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_grey.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_08_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_04_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_16_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_20_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_03_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_14_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_17_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_06_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_06_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_20_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_01_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_16_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_21_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_12_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_12_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_22_light.png", "res/drawable-xxhdpi-v4/ic_audiotrack_dark.png", "res/drawable-xxhdpi-v4/ic_media_play_light.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_19_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_05_dark.png", "res/drawable-xxhdpi-v4/ic_media_pause_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_22_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_14_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_11_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_00_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_08_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_13_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_18_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connecting_04_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_07_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_00_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_01_light.png", "res/drawable-xxhdpi-v4/ic_media_play_dark.png", "res/drawable-xxhdpi-v4/ic_mr_button_connected_03_light.png", "res/values-th/values-th.xml", "res/values-cs/values-cs.xml", "res/values-sr/values-sr.xml", "res/values-tl/values-tl.xml", "res/values-te-rIN/values-te-rIN.xml", "res/values-ne-rNP/values-ne-rNP.xml", "res/values-ta-rIN/values-ta-rIN.xml", "res/drawable/mr_button_connecting_light.xml", "res/drawable/mr_group_collapse.xml", "res/drawable/mr_button_connecting_dark.xml", "res/drawable/mr_dialog_close_dark.xml", "res/drawable/mr_vol_type_audiotrack_dark.xml", "res/drawable/mr_media_pause_light.xml", "res/drawable/mr_group_expand.xml", "res/drawable/mr_vol_type_audiotrack_light.xml", "res/drawable/mr_dialog_material_background_light.xml", "res/drawable/mr_media_play_dark.xml", "res/drawable/mr_button_dark.xml", "res/drawable/mr_media_pause_dark.xml", "res/drawable/mr_dialog_material_background_dark.xml", "res/drawable/mr_button_connected_light.xml", "res/drawable/mr_dialog_close_light.xml", "res/drawable/mr_media_play_light.xml", "res/drawable/mr_button_connected_dark.xml", "res/drawable/mr_button_light.xml" ]
+subjar_tuples = [ [ "internal_impl_25.0.1", "libs/internal_impl-25.0.1.jar" ] ]
+subjars = [ "libs/internal_impl-25.0.1.jar" ]
diff --git a/build/secondary/third_party/android_tools/support/android_support_v7_palette_java.info b/build/secondary/third_party/android_tools/support/android_support_v7_palette_java.info
new file mode 100644
index 0000000..a2ebd4a8
--- /dev/null
+++ b/build/secondary/third_party/android_tools/support/android_support_v7_palette_java.info
@@ -0,0 +1,13 @@
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+aidl = [  ]
+assets = [  ]
+has_classes_jar = true
+has_native_libraries = false
+has_proguard_flags = false
+has_r_text_file = false
+is_manifest_empty = true
+resources = [  ]
+subjar_tuples = [  ]
+subjars = [  ]
diff --git a/build/secondary/third_party/android_tools/support/android_support_v7_preference_java.info b/build/secondary/third_party/android_tools/support/android_support_v7_preference_java.info
new file mode 100644
index 0000000..fc60261
--- /dev/null
+++ b/build/secondary/third_party/android_tools/support/android_support_v7_preference_java.info
@@ -0,0 +1,13 @@
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+aidl = [  ]
+assets = [  ]
+has_classes_jar = true
+has_native_libraries = false
+has_proguard_flags = true
+has_r_text_file = true
+is_manifest_empty = true
+resources = [ "res/values-v17/values-v17.xml", "res/layout/preference_dropdown.xml", "res/layout/preference_list_fragment.xml", "res/layout/preference.xml", "res/layout/preference_category.xml", "res/layout/preference_widget_checkbox.xml", "res/layout/preference_widget_switch_compat.xml", "res/layout/preference_information.xml", "res/layout/preference_recyclerview.xml", "res/layout/preference_dialog_edittext.xml", "res/values/values.xml", "res/layout-v11/preference_dropdown.xml", "res/layout-v11/preference.xml" ]
+subjar_tuples = [  ]
+subjars = [  ]
diff --git a/build/secondary/third_party/android_tools/support/android_support_v7_recyclerview_java.info b/build/secondary/third_party/android_tools/support/android_support_v7_recyclerview_java.info
new file mode 100644
index 0000000..a25d255
--- /dev/null
+++ b/build/secondary/third_party/android_tools/support/android_support_v7_recyclerview_java.info
@@ -0,0 +1,13 @@
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+aidl = [  ]
+assets = [  ]
+has_classes_jar = true
+has_native_libraries = false
+has_proguard_flags = true
+has_r_text_file = true
+is_manifest_empty = true
+resources = [ "res/values/values.xml" ]
+subjar_tuples = [  ]
+subjars = [  ]
diff --git a/build/secondary/third_party/android_tools/support/android_support_vector_drawable_java.info b/build/secondary/third_party/android_tools/support/android_support_vector_drawable_java.info
new file mode 100644
index 0000000..a2ebd4a8
--- /dev/null
+++ b/build/secondary/third_party/android_tools/support/android_support_vector_drawable_java.info
@@ -0,0 +1,13 @@
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+aidl = [  ]
+assets = [  ]
+has_classes_jar = true
+has_native_libraries = false
+has_proguard_flags = false
+has_r_text_file = false
+is_manifest_empty = true
+resources = [  ]
+subjar_tuples = [  ]
+subjars = [  ]
diff --git a/build/util/lib/common/chrome_test_server_spawner.py b/build/util/lib/common/chrome_test_server_spawner.py
index 39b5528..8fac32b 100644
--- a/build/util/lib/common/chrome_test_server_spawner.py
+++ b/build/util/lib/common/chrome_test_server_spawner.py
@@ -157,13 +157,11 @@
       return False
     logging.info('Got port json data: %s', port_json)
     port_json = json.loads(port_json)
-
-    if not port_json.has_key('port') or not isinstance(port_json['port'], int):
-      logging.error('Failed to get port information from the server data.')
-      return False
-
-    self.host_port = port_json['port']
-    return self.port_forwarder.WaitPortNotAvailable(self.host_port)
+    if port_json.has_key('port') and isinstance(port_json['port'], int):
+      self.host_port = port_json['port']
+      return self.port_forwarder.WaitPortNotAvailable(self.host_port)
+    logging.error('Failed to get port information from the server data.')
+    return False
 
   def _GenerateCommandLineArguments(self):
     """Generates the command line to run the test server.
@@ -317,54 +315,43 @@
     logging.info(content_length)
     test_server_argument_json = self.rfile.read(content_length)
     logging.info(test_server_argument_json)
-
-    if len(self.server.test_servers) >= self.server.max_instances:
-      self._SendResponse(400, 'Invalid request', {},
-                         'Too many test servers running')
-      return
-
+    # There should only be one test server instance at a time. However it may
+    # be possible that a previous instance was not cleaned up properly
+    # (crbug.com/665686)
+    if self.server.test_server_instance:
+      port = self.server.test_server_instance.host_port
+      logging.info('Killing lingering test server instance on port: %d', port)
+      self.server.test_server_instance.Stop()
+      self.server.test_server_instance = None
     ready_event = threading.Event()
-    new_server = TestServerThread(ready_event,
-                                  json.loads(test_server_argument_json),
-                                  self.server.port_forwarder)
-    new_server.setDaemon(True)
-    new_server.start()
+    self.server.test_server_instance = TestServerThread(
+        ready_event,
+        json.loads(test_server_argument_json),
+        self.server.port_forwarder)
+    self.server.test_server_instance.setDaemon(True)
+    self.server.test_server_instance.start()
     ready_event.wait()
-    if new_server.is_ready:
+    if self.server.test_server_instance.is_ready:
       self._SendResponse(200, 'OK', {}, json.dumps(
-          {'port': new_server.forwarder_device_port,
+          {'port': self.server.test_server_instance.forwarder_device_port,
            'message': 'started'}))
-      port = new_server.host_port
-      logging.info('Test server is running on port: %d.' % port)
-      assert not self.server.test_servers.has_key(port)
-      self.server.test_servers[port] = new_server
+      logging.info('Test server is running on port: %d.',
+                   self.server.test_server_instance.host_port)
     else:
-      new_server.Stop()
+      self.server.test_server_instance.Stop()
+      self.server.test_server_instance = None
       self._SendResponse(500, 'Test Server Error.', {}, '')
       logging.info('Encounter problem during starting a test server.')
 
-  def _KillTestServer(self, params):
+  def _KillTestServer(self):
     """Stops the test server instance."""
     # There should only ever be one test server at a time. This may do the
     # wrong thing if we try and start multiple test servers.
-    try:
-      port = int(params['port'][0])
-    except ValueError, KeyError:
-      port = None
-    if port == None or port <= 0:
-      self._SendResponse(400, 'Invalid request.', {}, 'port must be specified')
+    if not self.server.test_server_instance:
       return
-
-    if not self.server.test_servers.has_key(port):
-      self._SendResponse(400, 'Invalid request.', {},
-                         "testserver isn't running on port %d" % port)
-      return
-
-    server = self.server.test_servers.pop(port)
-
+    port = self.server.test_server_instance.host_port
     logging.info('Handling request to kill a test server on port: %d.', port)
-    server.Stop()
-
+    self.server.test_server_instance.Stop()
     # Make sure the status of test server is correct before sending response.
     if self.server.port_forwarder.WaitHostPortAvailable(port):
       self._SendResponse(200, 'OK', {}, 'killed')
@@ -372,6 +359,7 @@
     else:
       self._SendResponse(500, 'Test Server Error.', {}, '')
       logging.info('Encounter problem during killing a test server.')
+    self.server.test_server_instance = None
 
   def do_POST(self):
     parsed_path = urlparse.urlparse(self.path)
@@ -391,7 +379,7 @@
     for param in params:
       logging.info('%s=%s', param, params[param][0])
     if action == '/kill':
-      self._KillTestServer(params)
+      self._KillTestServer()
     elif action == '/ping':
       # The ping handler is used to check whether the spawner server is ready
       # to serve the requests. We don't need to test the status of the test
@@ -406,18 +394,17 @@
 class SpawningServer(object):
   """The class used to start/stop a http server."""
 
-  def __init__(self, test_server_spawner_port, port_forwarder, max_instances):
+  def __init__(self, test_server_spawner_port, port_forwarder):
     self.server = BaseHTTPServer.HTTPServer(('', test_server_spawner_port),
                                             SpawningServerRequestHandler)
     self.server_port = self.server.server_port
     logging.info('Started test server spawner on port: %d.', self.server_port)
 
     self.server.port_forwarder = port_forwarder
-    self.server.test_servers = {}
-    self.server.max_instances = max_instances
+    self.server.test_server_instance = None
 
   def _Listen(self):
-    logging.info('Starting test server spawner.')
+    logging.info('Starting test server spawner')
     self.server.serve_forever()
 
   def Start(self):
@@ -440,9 +427,6 @@
     This should be called if the test server spawner is reused,
     to avoid sharing the test server instance.
     """
-    if self.server.test_servers:
-      logging.warning('Not all test servers were stopped.')
-      for port in self.server.test_servers:
-        logging.warning('Stopping test server on port %d' % port)
-        self.server.test_servers[port].Stop()
-      self.server.test_servers = {}
+    if self.server.test_server_instance:
+      self.server.test_server_instance.Stop()
+      self.server.test_server_instance = None
diff --git a/cc/ipc/BUILD.gn b/cc/ipc/BUILD.gn
index dbd5257..9e85e5b2d 100644
--- a/cc/ipc/BUILD.gn
+++ b/cc/ipc/BUILD.gn
@@ -41,8 +41,6 @@
   sources = [
     "copy_output_request.mojom",
     "copy_output_result.mojom",
-    "filter_operation.mojom",
-    "filter_operations.mojom",
     "frame_sink_id.mojom",
     "local_surface_id.mojom",
     "texture_mailbox.mojom",
diff --git a/cc/ipc/filter_operation.typemap b/cc/ipc/filter_operation.typemap
deleted file mode 100644
index b892dc3..0000000
--- a/cc/ipc/filter_operation.typemap
+++ /dev/null
@@ -1,8 +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.
-
-mojom = "//cc/ipc/filter_operation.mojom"
-public_headers = [ "//cc/base/filter_operation.h" ]
-traits_headers = [ "//cc/ipc/filter_operation_struct_traits.h" ]
-type_mappings = [ "cc.mojom.FilterOperation=cc::FilterOperation" ]
diff --git a/cc/ipc/filter_operations.typemap b/cc/ipc/filter_operations.typemap
deleted file mode 100644
index e675a1a..0000000
--- a/cc/ipc/filter_operations.typemap
+++ /dev/null
@@ -1,8 +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.
-
-mojom = "//cc/ipc/filter_operations.mojom"
-public_headers = [ "//cc/base/filter_operations.h" ]
-traits_headers = [ "//cc/ipc/filter_operations_struct_traits.h" ]
-type_mappings = [ "cc.mojom.FilterOperations=cc::FilterOperations" ]
diff --git a/cc/ipc/filter_operations_struct_traits.h b/cc/ipc/filter_operations_struct_traits.h
deleted file mode 100644
index 5e77f814..0000000
--- a/cc/ipc/filter_operations_struct_traits.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_IPC_FILTER_OPERATIONS_STRUCT_TRAITS_H_
-#define CC_IPC_FILTER_OPERATIONS_STRUCT_TRAITS_H_
-
-#include "cc/base/filter_operations.h"
-#include "cc/ipc/filter_operations.mojom-shared.h"
-
-namespace mojo {
-
-template <>
-struct StructTraits<cc::mojom::FilterOperationsDataView, cc::FilterOperations> {
-  static const std::vector<cc::FilterOperation>& operations(
-      const cc::FilterOperations& operations) {
-    return operations.operations();
-  }
-
-  static bool Read(cc::mojom::FilterOperationsDataView data,
-                   cc::FilterOperations* out) {
-    std::vector<cc::FilterOperation> operations;
-    if (!data.ReadOperations(&operations))
-      return false;
-    *out = cc::FilterOperations(std::move(operations));
-    return true;
-  }
-};
-
-}  // namespace mojo
-
-#endif  // CC_IPC_FILTER_OPERATIONS_STRUCT_TRAITS_H_
diff --git a/cc/ipc/struct_traits_unittest.cc b/cc/ipc/struct_traits_unittest.cc
index 1f330987..6ae6766 100644
--- a/cc/ipc/struct_traits_unittest.cc
+++ b/cc/ipc/struct_traits_unittest.cc
@@ -51,16 +51,6 @@
     std::move(callback).Run(std::move(c));
   }
 
-  void EchoFilterOperation(const FilterOperation& f,
-                           EchoFilterOperationCallback callback) override {
-    std::move(callback).Run(f);
-  }
-
-  void EchoFilterOperations(const FilterOperations& f,
-                            EchoFilterOperationsCallback callback) override {
-    std::move(callback).Run(f);
-  }
-
   void EchoTextureMailbox(const viz::TextureMailbox& t,
                           EchoTextureMailboxCallback callback) override {
     std::move(callback).Run(t);
@@ -248,75 +238,6 @@
   run_loop.Run();
 }
 
-TEST_F(StructTraitsTest, FilterOperation) {
-  const FilterOperation inputs[] = {
-      FilterOperation::CreateBlurFilter(20),
-      FilterOperation::CreateDropShadowFilter(gfx::Point(4, 4), 4.0f,
-                                              SkColorSetARGB(255, 40, 0, 0)),
-      FilterOperation::CreateReferenceFilter(SkDropShadowImageFilter::Make(
-          SkIntToScalar(3), SkIntToScalar(8), SkIntToScalar(4),
-          SkIntToScalar(9), SK_ColorBLACK,
-          SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
-          nullptr))};
-  mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy();
-  for (const auto& input : inputs) {
-    FilterOperation output;
-    proxy->EchoFilterOperation(input, &output);
-    EXPECT_EQ(input.type(), output.type());
-    switch (input.type()) {
-      case FilterOperation::GRAYSCALE:
-      case FilterOperation::SEPIA:
-      case FilterOperation::SATURATE:
-      case FilterOperation::HUE_ROTATE:
-      case FilterOperation::INVERT:
-      case FilterOperation::BRIGHTNESS:
-      case FilterOperation::SATURATING_BRIGHTNESS:
-      case FilterOperation::CONTRAST:
-      case FilterOperation::OPACITY:
-      case FilterOperation::BLUR:
-        EXPECT_EQ(input.amount(), output.amount());
-        break;
-      case FilterOperation::DROP_SHADOW:
-        EXPECT_EQ(input.amount(), output.amount());
-        EXPECT_EQ(input.drop_shadow_offset(), output.drop_shadow_offset());
-        EXPECT_EQ(input.drop_shadow_color(), output.drop_shadow_color());
-        break;
-      case FilterOperation::COLOR_MATRIX:
-        EXPECT_EQ(0, memcmp(input.matrix(), output.matrix(), 20));
-        break;
-      case FilterOperation::ZOOM:
-        EXPECT_EQ(input.amount(), output.amount());
-        EXPECT_EQ(input.zoom_inset(), output.zoom_inset());
-        break;
-      case FilterOperation::REFERENCE: {
-        SkString input_str;
-        input.image_filter()->toString(&input_str);
-        SkString output_str;
-        output.image_filter()->toString(&output_str);
-        EXPECT_EQ(input_str, output_str);
-        break;
-      }
-      case FilterOperation::ALPHA_THRESHOLD:
-        NOTREACHED();
-        break;
-    }
-  }
-}
-
-TEST_F(StructTraitsTest, FilterOperations) {
-  FilterOperations input;
-  input.Append(FilterOperation::CreateBlurFilter(0.f));
-  input.Append(FilterOperation::CreateSaturateFilter(4.f));
-  input.Append(FilterOperation::CreateZoomFilter(2.0f, 1));
-  mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy();
-  FilterOperations output;
-  proxy->EchoFilterOperations(input, &output);
-  EXPECT_EQ(input.size(), output.size());
-  for (size_t i = 0; i < input.size(); ++i) {
-    EXPECT_EQ(input.at(i), output.at(i));
-  }
-}
-
 TEST_F(StructTraitsTest, TextureMailbox) {
   const int8_t mailbox_name[GL_MAILBOX_SIZE_CHROMIUM] = {
       0, 9, 8, 7, 6, 5, 4, 3, 2, 1, 9, 7, 5, 3, 1, 2};
diff --git a/cc/ipc/traits_test_service.mojom b/cc/ipc/traits_test_service.mojom
index 681a2fd38..b3aaa45 100644
--- a/cc/ipc/traits_test_service.mojom
+++ b/cc/ipc/traits_test_service.mojom
@@ -6,8 +6,6 @@
 
 import "cc/ipc/copy_output_request.mojom";
 import "cc/ipc/copy_output_result.mojom";
-import "cc/ipc/filter_operation.mojom";
-import "cc/ipc/filter_operations.mojom";
 import "cc/ipc/texture_mailbox.mojom";
 
 // All functions on this interface echo their arguments to test StructTraits
@@ -20,12 +18,6 @@
   EchoCopyOutputResult(CopyOutputResult c) => (CopyOutputResult pass);
 
   [Sync]
-  EchoFilterOperation(FilterOperation f) => (FilterOperation pass);
-
-  [Sync]
-  EchoFilterOperations(FilterOperations f) => (FilterOperations pass);
-
-  [Sync]
   EchoTextureMailbox(TextureMailbox t) =>
       (TextureMailbox pass);
 };
diff --git a/cc/ipc/typemaps.gni b/cc/ipc/typemaps.gni
index f4069919..b1270af9 100644
--- a/cc/ipc/typemaps.gni
+++ b/cc/ipc/typemaps.gni
@@ -5,8 +5,6 @@
 typemaps = [
   "//cc/ipc/copy_output_request.typemap",
   "//cc/ipc/copy_output_result.typemap",
-  "//cc/ipc/filter_operation.typemap",
-  "//cc/ipc/filter_operations.typemap",
   "//cc/ipc/frame_sink_id.typemap",
   "//cc/ipc/local_surface_id.typemap",
   "//cc/ipc/texture_mailbox.typemap",
diff --git a/cc/output/direct_renderer.cc b/cc/output/direct_renderer.cc
index ee9e5b5..be0f7c7 100644
--- a/cc/output/direct_renderer.cc
+++ b/cc/output/direct_renderer.cc
@@ -309,8 +309,6 @@
     output_surface_plane.display_rect =
         gfx::RectF(root_render_pass->output_rect);
     output_surface_plane.format = output_surface_->GetOverlayBufferFormat();
-    output_surface_plane.quad_rect_in_target_space =
-        root_render_pass->output_rect;
     output_surface_plane.use_output_surface_for_resource = true;
     output_surface_plane.overlay_handled = true;
     current_frame()->overlay_list.push_back(output_surface_plane);
diff --git a/cc/output/overlay_candidate.cc b/cc/output/overlay_candidate.cc
index 14f5ca4..b4583c4 100644
--- a/cc/output/overlay_candidate.cc
+++ b/cc/output/overlay_candidate.cc
@@ -276,8 +276,6 @@
   auto& transform = quad->shared_quad_state->quad_to_target_transform;
   candidate->display_rect = gfx::RectF(quad->rect);
   transform.TransformRect(&candidate->display_rect);
-  candidate->quad_rect_in_target_space =
-      MathUtil::MapEnclosingClippedRect(transform, quad->rect);
 
   candidate->clip_rect = quad->shared_quad_state->clip_rect;
   candidate->is_clipped = quad->shared_quad_state->is_clipped;
diff --git a/cc/output/overlay_candidate.h b/cc/output/overlay_candidate.h
index a3ee59b..fdd0f7e60 100644
--- a/cc/output/overlay_candidate.h
+++ b/cc/output/overlay_candidate.h
@@ -62,8 +62,6 @@
   gfx::RectF display_rect;
   // Crop within the buffer to be placed inside |display_rect|.
   gfx::RectF uv_rect;
-  // Quad geometry rect after applying the quad_transform().
-  gfx::Rect quad_rect_in_target_space;
   // Clip rect in the target content space after composition.
   gfx::Rect clip_rect;
   // If the quad is clipped after composition.
diff --git a/cc/output/overlay_unittest.cc b/cc/output/overlay_unittest.cc
index 114ce1c..9d41242 100644
--- a/cc/output/overlay_unittest.cc
+++ b/cc/output/overlay_unittest.cc
@@ -803,7 +803,6 @@
   // Primary plane.
   OverlayCandidate output_surface_plane;
   output_surface_plane.display_rect = gfx::RectF(kOverlayRect);
-  output_surface_plane.quad_rect_in_target_space = kOverlayRect;
   output_surface_plane.use_output_surface_for_resource = true;
   output_surface_plane.overlay_handled = true;
   candidate_list.push_back(output_surface_plane);
@@ -1810,8 +1809,6 @@
   OverlayCandidateList list;
   OverlayCandidate output_surface_plane;
   output_surface_plane.display_rect = gfx::RectF(root_render_pass->output_rect);
-  output_surface_plane.quad_rect_in_target_space =
-      root_render_pass->output_rect;
   output_surface_plane.use_output_surface_for_resource = true;
   output_surface_plane.overlay_handled = true;
   list.push_back(output_surface_plane);
diff --git a/cc/paint/paint_op_reader.cc b/cc/paint/paint_op_reader.cc
index 6bd74ba..692c5ac 100644
--- a/cc/paint/paint_op_reader.cc
+++ b/cc/paint/paint_op_reader.cc
@@ -16,6 +16,9 @@
 namespace cc {
 namespace {
 
+// If we have more than this many colors, abort deserialization.
+const size_t kMaxShaderColorsSupported = 10000;
+
 bool IsValidPaintShaderType(PaintShader::Type type) {
   return static_cast<uint8_t>(type) <
          static_cast<uint8_t>(PaintShader::Type::kShaderCount);
@@ -247,8 +250,8 @@
   decltype(ref.colors_)::size_type colors_size = 0;
   ReadSimple(&colors_size);
 
-  // If colors_bytes would overflow, then definitely too many.
-  if (colors_size > std::numeric_limits<size_t>::max() / sizeof(SkColor)) {
+  // If there are too many colors, abort.
+  if (colors_size > kMaxShaderColorsSupported) {
     valid_ = false;
     return;
   }
@@ -257,8 +260,6 @@
     valid_ = false;
     return;
   }
-  // TODO(enne): maybe we should cap the number of colors or positions to
-  // something much more reasonable, e.g. 1k?
   ref.colors_.resize(colors_size);
   ReadData(colors_bytes, ref.colors_.data());
 
diff --git a/cc/paint/paint_shader.cc b/cc/paint/paint_shader.cc
index 7d5d710..2257e6a 100644
--- a/cc/paint/paint_shader.cc
+++ b/cc/paint/paint_shader.cc
@@ -220,7 +220,11 @@
 void PaintShader::SetColorsAndPositions(const SkColor* colors,
                                         const SkScalar* positions,
                                         int count) {
+#if DCHECK_IS_ON()
+  static const int kMaxShaderColorsSupported = 10000;
   DCHECK_GE(count, 2);
+  DCHECK_LE(count, kMaxShaderColorsSupported);
+#endif
   colors_.assign(colors, colors + count);
   if (positions)
     positions_.assign(positions, positions + count);
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 9cb0d9f..094e63e 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -2833,6 +2833,16 @@
         MainThreadScrollingReason::kNoScrollingLayer;
     return scroll_status;
   }
+
+  if (touchpad_and_wheel_scroll_latching_enabled_) {
+    // TODO(chaopeng) ScrollBegin and ScrollEnd will apply to same layer after
+    // TouchpadAndWheelScrollLatching land.
+    ScrollbarAnimationController* animation_controller =
+        ScrollbarAnimationControllerForElementId(scrolling_node->element_id);
+    if (animation_controller)
+      animation_controller->DidScrollBegin();
+  }
+
   scroll_status.thread = SCROLL_ON_IMPL_THREAD;
   mutator_host_->ScrollAnimationAbort();
 
@@ -2948,11 +2958,23 @@
     RecordCompositorSlowScrollMetric(type, MAIN_THREAD);
 
     scroll_status.thread = SCROLL_ON_MAIN_THREAD;
+
+    // TODO(chaopeng) ScrollBegin and ScrollEnd will apply to same layer after
+    // TouchpadAndWheelScrollLatching land. impl scroll will call scroll begin
+    // in ScrollBeginImpl.
+    if (touchpad_and_wheel_scroll_latching_enabled_ && scrolling_node) {
+      ScrollbarAnimationController* animation_controller =
+          ScrollbarAnimationControllerForElementId(scrolling_node->element_id);
+      if (animation_controller)
+        animation_controller->DidScrollBegin();
+    }
+
     return scroll_status;
-  } else if (scrolling_node) {
-    scroll_affects_scroll_handler_ = active_tree_->have_scroll_event_handlers();
   }
 
+  if (scrolling_node)
+    scroll_affects_scroll_handler_ = active_tree_->have_scroll_event_handlers();
+
   return ScrollBeginImpl(scroll_state, scrolling_node, type);
 }
 
@@ -3624,6 +3646,18 @@
 
   DistributeScrollDelta(scroll_state);
   browser_controls_offset_manager_->ScrollEnd();
+
+  // TODO(chaopeng) ScrollBegin and ScrollEnd will apply to same layer after
+  // TouchpadAndWheelScrollLatching land.
+  if (touchpad_and_wheel_scroll_latching_enabled_) {
+    if (ScrollNode* scrolling_node = CurrentlyScrollingNode()) {
+      ScrollbarAnimationController* scrollbar_animation_controller =
+          ScrollbarAnimationControllerForElementId(scrolling_node->element_id);
+      if (scrollbar_animation_controller)
+        scrollbar_animation_controller->DidScrollEnd();
+    }
+  }
+
   ClearCurrentlyScrollingNode();
 }
 
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index d3ec47e..c384d0c 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -3042,7 +3042,9 @@
   base::TimeTicks fake_current_physical_time_;
 };
 
-class LayerTreeHostImplTestScrollbarAnimation : public LayerTreeHostImplTest {
+class LayerTreeHostImplTestScrollbarAnimation
+    : public ::testing::WithParamInterface<bool>,
+      public LayerTreeHostImplTest {
  protected:
   void SetupLayers(LayerTreeSettings settings) {
     host_impl_->ReleaseLayerTreeFrameSink();
@@ -3085,6 +3087,8 @@
   }
 
   void RunTest(LayerTreeSettings::ScrollbarAnimator animator) {
+    bool latching = GetParam();
+
     LayerTreeSettings settings = DefaultSettings();
     settings.scrollbar_animator = animator;
     settings.scrollbar_fade_delay = base::TimeDelta::FromMilliseconds(20);
@@ -3095,6 +3099,10 @@
 
     SetupLayers(settings);
 
+    // Enable wheel scroll latching flag.
+    TestInputHandlerClient input_handler_client;
+    host_impl_->BindToClient(&input_handler_client, latching);
+
     base::TimeTicks fake_now = base::TimeTicks::Now();
 
     // Android Overlay Scrollbar does not have a initial show and fade out.
@@ -3126,15 +3134,31 @@
     host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
                             InputHandler::WHEEL);
     host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2dF(0, 0)).get());
+    if (expecting_animations) {
+      if (latching) {
+        EXPECT_FALSE(did_request_next_frame_);
+        EXPECT_FALSE(did_request_redraw_);
+        EXPECT_EQ(base::TimeDelta(), requested_animation_delay_);
+        EXPECT_TRUE(animation_task_.Equals(base::Closure()));
+      } else if (animator == LayerTreeSettings::AURA_OVERLAY) {
+        EXPECT_FALSE(did_request_redraw_);
+        EXPECT_EQ(base::TimeDelta::FromMilliseconds(20),
+                  requested_animation_delay_);
+        EXPECT_FALSE(animation_task_.Equals(base::Closure()));
+        requested_animation_delay_ = base::TimeDelta();
+        animation_task_ = base::Closure();
+      }
+    }
     host_impl_->ScrollEnd(EndState().get());
     EXPECT_FALSE(did_request_next_frame_);
     EXPECT_FALSE(did_request_redraw_);
-    if (animator == LayerTreeSettings::AURA_OVERLAY) {
+    if (animator == LayerTreeSettings::AURA_OVERLAY && latching) {
       EXPECT_EQ(base::TimeDelta::FromMilliseconds(20),
                 requested_animation_delay_);
       EXPECT_FALSE(animation_task_.Equals(base::Closure()));
       requested_animation_delay_ = base::TimeDelta();
       animation_task_ = base::Closure();
+      did_request_redraw_ = false;
     } else {
       EXPECT_EQ(base::TimeDelta(), requested_animation_delay_);
       EXPECT_TRUE(animation_task_.Equals(base::Closure()));
@@ -3153,36 +3177,37 @@
     EXPECT_TRUE(animation_task_.Equals(base::Closure()));
     host_impl_->DidFinishImplFrame();
 
-    // After a scroll, a scrollbar animation should be scheduled about 20ms from
-    // now.
+    // After a scroll, a scrollbar animation should not be scheduled after
+    // ScrollBegin with latching.
     host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
                             InputHandler::WHEEL);
     host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2dF(0, 5)).get());
     EXPECT_FALSE(did_request_next_frame_);
-    EXPECT_TRUE(did_request_redraw_);
-    did_request_redraw_ = false;
     if (expecting_animations) {
-      EXPECT_EQ(base::TimeDelta::FromMilliseconds(20),
-                requested_animation_delay_);
-      EXPECT_FALSE(animation_task_.Equals(base::Closure()));
-    } else {
-      EXPECT_EQ(base::TimeDelta(), requested_animation_delay_);
-      EXPECT_TRUE(animation_task_.Equals(base::Closure()));
+      // With latching, ScrollUpdate after ScrollBegin should not schedule a
+      // delay fadeout. Without latching, ScrollUpdate should always schedule a
+      // new delay fadeout.
+      if (latching) {
+        EXPECT_EQ(base::TimeDelta(), requested_animation_delay_);
+        EXPECT_TRUE(animation_task_.Equals(base::Closure()));
+      } else {
+        EXPECT_EQ(base::TimeDelta::FromMilliseconds(20),
+                  requested_animation_delay_);
+        EXPECT_FALSE(animation_task_.Equals(base::Closure()));
+        requested_animation_delay_ = base::TimeDelta();
+        animation_task_ = base::Closure();
+      }
     }
+    did_request_redraw_ = false;
 
     host_impl_->ScrollEnd(EndState().get());
     EXPECT_FALSE(did_request_next_frame_);
     EXPECT_FALSE(did_request_redraw_);
-    if (expecting_animations) {
+
+    if (expecting_animations && latching) {
       EXPECT_EQ(base::TimeDelta::FromMilliseconds(20),
                 requested_animation_delay_);
       EXPECT_FALSE(animation_task_.Equals(base::Closure()));
-    } else {
-      EXPECT_EQ(base::TimeDelta(), requested_animation_delay_);
-      EXPECT_TRUE(animation_task_.Equals(base::Closure()));
-    }
-
-    if (expecting_animations) {
       // Before the scrollbar animation begins, we should not get redraws.
       begin_frame_args = viz::CreateBeginFrameArgsForTesting(
           BEGINFRAME_FROM_HERE, 0, 3, fake_now);
@@ -3215,8 +3240,10 @@
       EXPECT_EQ(base::TimeDelta(), requested_animation_delay_);
       EXPECT_TRUE(animation_task_.Equals(base::Closure()));
       host_impl_->DidFinishImplFrame();
+    } else {
+      EXPECT_EQ(base::TimeDelta(), requested_animation_delay_);
+      EXPECT_TRUE(animation_task_.Equals(base::Closure()));
     }
-
     // Setting the scroll offset outside a scroll should not cause the
     // scrollbar to appear or schedule a scrollbar animation.
     if (host_impl_->active_tree()
@@ -3246,18 +3273,26 @@
       EXPECT_EQ(base::TimeDelta(), requested_animation_delay_);
       EXPECT_TRUE(animation_task_.Equals(base::Closure()));
     }
+
+    // Tear down the LayerTreeHostImpl before the InputHandlerClient.
+    host_impl_->ReleaseLayerTreeFrameSink();
+    host_impl_ = nullptr;
   }
 };
 
-TEST_F(LayerTreeHostImplTestScrollbarAnimation, Android) {
+INSTANTIATE_TEST_CASE_P(All,
+                        LayerTreeHostImplTestScrollbarAnimation,
+                        ::testing::Bool());
+
+TEST_P(LayerTreeHostImplTestScrollbarAnimation, Android) {
   RunTest(LayerTreeSettings::ANDROID_OVERLAY);
 }
 
-TEST_F(LayerTreeHostImplTestScrollbarAnimation, AuraOverlay) {
+TEST_P(LayerTreeHostImplTestScrollbarAnimation, AuraOverlay) {
   RunTest(LayerTreeSettings::AURA_OVERLAY);
 }
 
-TEST_F(LayerTreeHostImplTestScrollbarAnimation, NoAnimator) {
+TEST_P(LayerTreeHostImplTestScrollbarAnimation, NoAnimator) {
   RunTest(LayerTreeSettings::NO_ANIMATOR);
 }
 
diff --git a/cc/trees/property_tree_builder.cc b/cc/trees/property_tree_builder.cc
index 390120ac..9a57979 100644
--- a/cc/trees/property_tree_builder.cc
+++ b/cc/trees/property_tree_builder.cc
@@ -32,15 +32,8 @@
 
 template <typename LayerType>
 struct DataForRecursion {
-  PropertyTrees* property_trees;
-  LayerType* transform_tree_parent;
-  LayerType* transform_fixed_parent;
-  const LayerType* page_scale_layer;
-  const LayerType* inner_viewport_scroll_layer;
-  const LayerType* outer_viewport_scroll_layer;
-  const LayerType* overscroll_elasticity_layer;
-  const gfx::Transform* device_transform;
-  float page_scale_factor;
+  int transform_tree_parent;
+  int transform_tree_parent_fixed;
   int clip_tree_parent;
   int effect_tree_parent;
   int scroll_tree_parent;
@@ -49,15 +42,82 @@
   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;
   bool scroll_tree_parent_created_by_uninheritable_criteria;
   bool animation_axis_aligned_since_render_target;
   bool not_axis_aligned_since_last_clip;
   gfx::Transform compound_transform_since_render_target;
-  gfx::Vector2dF elastic_overscroll;
+};
+
+template <typename LayerType>
+class PropertyTreeBuilderContext {
+ public:
+  PropertyTreeBuilderContext(const LayerType* page_scale_layer,
+                             const LayerType* inner_viewport_scroll_layer,
+                             const LayerType* outer_viewport_scroll_layer,
+                             const LayerType* overscroll_elasticity_layer,
+                             const gfx::Vector2dF& elastic_overscroll,
+                             float page_scale_factor,
+                             const gfx::Transform& device_transform,
+                             PropertyTrees& property_trees)
+      : page_scale_layer_(page_scale_layer),
+        inner_viewport_scroll_layer_(inner_viewport_scroll_layer),
+        outer_viewport_scroll_layer_(outer_viewport_scroll_layer),
+        overscroll_elasticity_layer_(overscroll_elasticity_layer),
+        elastic_overscroll_(elastic_overscroll),
+        page_scale_factor_(page_scale_factor),
+        device_transform_(device_transform),
+        property_trees_(property_trees),
+        transform_tree_(property_trees.transform_tree),
+        clip_tree_(property_trees.clip_tree),
+        effect_tree_(property_trees.effect_tree),
+        scroll_tree_(property_trees.scroll_tree) {}
+
+  void BuildPropertyTrees(LayerType* root_layer,
+                          float device_scale_factor,
+                          const gfx::Rect& viewport,
+                          SkColor root_background_color) const;
+
+ private:
+  void BuildPropertyTreesInternal(
+      LayerType* layer,
+      const DataForRecursion<LayerType>& data_from_parent) const;
+
+  bool AddTransformNodeIfNeeded(
+      const DataForRecursion<LayerType>& data_from_ancestor,
+      LayerType* layer,
+      bool created_render_surface,
+      DataForRecursion<LayerType>* data_for_children) const;
+
+  void AddClipNodeIfNeeded(
+      const DataForRecursion<LayerType>& data_from_ancestor,
+      LayerType* layer,
+      bool created_transform_node,
+      DataForRecursion<LayerType>* data_for_children) const;
+
+  bool AddEffectNodeIfNeeded(
+      const DataForRecursion<LayerType>& data_from_ancestor,
+      LayerType* layer,
+      DataForRecursion<LayerType>* data_for_children) const;
+
+  void AddScrollNodeIfNeeded(
+      const DataForRecursion<LayerType>& data_from_ancestor,
+      LayerType* layer,
+      DataForRecursion<LayerType>* data_for_children) const;
+
+  const LayerType* page_scale_layer_;
+  const LayerType* inner_viewport_scroll_layer_;
+  const LayerType* outer_viewport_scroll_layer_;
+  const LayerType* overscroll_elasticity_layer_;
+  const gfx::Vector2dF elastic_overscroll_;
+  float page_scale_factor_;
+  const gfx::Transform& device_transform_;
+  PropertyTrees& property_trees_;
+  TransformTree& transform_tree_;
+  ClipTree& clip_tree_;
+  EffectTree& effect_tree_;
+  ScrollTree& scroll_tree_;
 };
 
 static LayerPositionConstraint PositionConstraint(Layer* layer) {
@@ -200,10 +260,10 @@
 // -------------------------------------------------------------------
 
 template <typename LayerType>
-static LayerType* GetTransformParent(const DataForRecursion<LayerType>& data,
-                                     LayerType* layer) {
+static int GetTransformParent(const DataForRecursion<LayerType>& data,
+                              LayerType* layer) {
   return PositionConstraint(layer).is_fixed_position()
-             ? data.transform_fixed_parent
+             ? data.transform_tree_parent_fixed
              : data.transform_tree_parent;
 }
 
@@ -254,16 +314,16 @@
 }
 
 template <typename LayerType>
-void AddClipNodeIfNeeded(const DataForRecursion<LayerType>& data_from_ancestor,
-                         LayerType* layer,
-                         bool created_transform_node,
-                         DataForRecursion<LayerType>* data_for_children) {
+void PropertyTreeBuilderContext<LayerType>::AddClipNodeIfNeeded(
+    const DataForRecursion<LayerType>& data_from_ancestor,
+    LayerType* layer,
+    bool created_transform_node,
+    DataForRecursion<LayerType>* data_for_children) const {
   const bool inherits_clip = !ClipParent(layer);
   // Sanity check the clip parent already built clip node before us.
   DCHECK(inherits_clip ||
-         HasLatestSequenceNumber(
-             ClipParent(layer),
-             data_from_ancestor.property_trees->sequence_number));
+         HasLatestSequenceNumber(ClipParent(layer),
+                                 property_trees_.sequence_number));
   const int parent_id = inherits_clip ? data_from_ancestor.clip_tree_parent
                                       : ClipParent(layer)->clip_tree_index();
 
@@ -273,15 +333,12 @@
   if (!requires_node) {
     data_for_children->clip_tree_parent = parent_id;
   } else {
-    LayerType* transform_parent = data_for_children->transform_tree_parent;
-    if (PositionConstraint(layer).is_fixed_position() &&
-        !created_transform_node) {
-      transform_parent = data_for_children->transform_fixed_parent;
-    }
     ClipNode node;
     node.clip = gfx::RectF(gfx::PointF() + layer->offset_to_transform_parent(),
                            gfx::SizeF(layer->bounds()));
-    node.transform_id = transform_parent->transform_tree_index();
+    node.transform_id = created_transform_node
+                            ? data_for_children->transform_tree_parent
+                            : GetTransformParent(data_from_ancestor, layer);
     if (layer_clips_subtree) {
       node.clip_type = ClipNode::ClipType::APPLIES_LOCAL_CLIP;
     } else {
@@ -290,8 +347,7 @@
       node.clip_expander =
           std::make_unique<ClipExpander>(layer->effect_tree_index());
     }
-    data_for_children->clip_tree_parent =
-        data_for_children->property_trees->clip_tree.Insert(node, parent_id);
+    data_for_children->clip_tree_parent = clip_tree_.Insert(node, parent_id);
   }
 
   layer->SetClipTreeIndex(data_for_children->clip_tree_parent);
@@ -329,15 +385,15 @@
 }
 
 template <typename LayerType>
-bool AddTransformNodeIfNeeded(
+bool PropertyTreeBuilderContext<LayerType>::AddTransformNodeIfNeeded(
     const DataForRecursion<LayerType>& data_from_ancestor,
     LayerType* layer,
     bool created_render_surface,
-    DataForRecursion<LayerType>* data_for_children) {
+    DataForRecursion<LayerType>* data_for_children) const {
   const bool is_root = !Parent(layer);
-  const bool is_page_scale_layer = layer == data_from_ancestor.page_scale_layer;
+  const bool is_page_scale_layer = layer == page_scale_layer_;
   const bool is_overscroll_elasticity_layer =
-      layer == data_from_ancestor.overscroll_elasticity_layer;
+      layer == overscroll_elasticity_layer_;
   const bool is_scrollable = layer->scrollable();
   const bool is_fixed = PositionConstraint(layer).is_fixed_position();
   const bool is_sticky = StickyPositionConstraint(layer).is_sticky;
@@ -375,11 +431,8 @@
   int source_index = TransformTree::kRootNodeId;
   gfx::Vector2dF source_offset;
 
-  LayerType* transform_parent = GetTransformParent(data_from_ancestor, layer);
-  DCHECK_EQ(is_root, !transform_parent);
-
-  if (transform_parent) {
-    parent_index = transform_parent->transform_tree_index();
+  if (!is_root) {
+    parent_index = GetTransformParent(data_from_ancestor, layer);
     // Because Blink still provides positions with respect to the parent layer,
     // we track both a parent TransformNode (which is the parent in the
     // TransformTree) and a 'source' TransformNode (which is the TransformNode
@@ -393,12 +446,15 @@
         layer->IsResizedByBrowserControls();
     if (is_scrollable) {
       DCHECK(Transform(layer).IsIdentity());
-      data_for_children->transform_fixed_parent = Parent(layer);
+      if (!is_root) {
+        data_for_children->transform_tree_parent_fixed =
+            Parent(layer)->transform_tree_index();
+      }
     } else {
-      data_for_children->transform_fixed_parent = layer;
+      data_for_children->transform_tree_parent_fixed =
+          requires_node ? transform_tree_.next_available_id() : parent_index;
     }
   }
-  data_for_children->transform_tree_parent = layer;
 
   if (!requires_node) {
     data_for_children->should_flatten |= ShouldFlattenTransform(layer);
@@ -407,8 +463,8 @@
     gfx::Vector2dF source_to_parent;
     if (source_index != parent_index) {
       gfx::Transform to_parent;
-      data_from_ancestor.property_trees->transform_tree.ComputeTranslation(
-          source_index, parent_index, &to_parent);
+      transform_tree_.ComputeTranslation(source_index, parent_index,
+                                         &to_parent);
       source_to_parent = to_parent.To2dTranslation();
     }
     layer->set_offset_to_transform_parent(source_offset + source_to_parent +
@@ -419,18 +475,16 @@
     return false;
   }
 
-  data_for_children->property_trees->transform_tree.Insert(TransformNode(),
-                                                           parent_index);
-
-  TransformNode* node =
-      data_for_children->property_trees->transform_tree.back();
+  transform_tree_.Insert(TransformNode(), parent_index);
+  TransformNode* node = transform_tree_.back();
   layer->SetTransformTreeIndex(node->id);
+  data_for_children->transform_tree_parent = node->id;
 
   // For animation subsystem purposes, if this layer has a compositor element
   // id, we build a map from that id to this transform node.
   if (layer->element_id()) {
-    data_for_children->property_trees
-        ->element_id_to_transform_node_index[layer->element_id()] = node->id;
+    property_trees_.element_id_to_transform_node_index[layer->element_id()] =
+        node->id;
     node->element_id = layer->element_id();
   }
 
@@ -440,7 +494,7 @@
 
   node->sorting_context_id = SortingContextId(layer);
 
-  if (layer == data_from_ancestor.page_scale_layer)
+  if (layer == page_scale_layer_)
     data_for_children->in_subtree_of_page_scale_layer = true;
   node->in_subtree_of_page_scale_layer =
       data_for_children->in_subtree_of_page_scale_layer;
@@ -448,7 +502,6 @@
   // Surfaces inherently flatten transforms.
   data_for_children->should_flatten =
       ShouldFlattenTransform(layer) || has_surface;
-  DCHECK_GT(data_from_ancestor.property_trees->effect_tree.size(), 0u);
 
   node->has_potential_animation = has_potentially_animated_transform;
   node->is_currently_animating = TransformIsAnimating(layer);
@@ -461,22 +514,18 @@
 
   if (is_page_scale_layer) {
     if (!is_root)
-      post_local_scale_factor *= data_from_ancestor.page_scale_factor;
-    data_for_children->property_trees->transform_tree.set_page_scale_factor(
-        data_from_ancestor.page_scale_factor);
+      post_local_scale_factor *= page_scale_factor_;
+    transform_tree_.set_page_scale_factor(page_scale_factor_);
   }
 
   node->source_node_id = source_index;
   node->post_local_scale_factor = post_local_scale_factor;
   if (is_root) {
     float page_scale_factor_for_root =
-        is_page_scale_layer ? data_from_ancestor.page_scale_factor : 1.f;
-    data_for_children->property_trees->transform_tree
-        .SetRootTransformsAndScales(data_for_children->property_trees
-                                        ->transform_tree.device_scale_factor(),
-                                    page_scale_factor_for_root,
-                                    *data_from_ancestor.device_transform,
-                                    layer->position());
+        is_page_scale_layer ? page_scale_factor_ : 1.f;
+    transform_tree_.SetRootTransformsAndScales(
+        transform_tree_.device_scale_factor(), page_scale_factor_for_root,
+        device_transform_, layer->position());
   } else {
     node->source_offset = source_offset;
     node->update_post_local_transform(layer->position(),
@@ -485,8 +534,7 @@
 
   if (is_overscroll_elasticity_layer) {
     DCHECK(!is_scrollable);
-    node->scroll_offset =
-        gfx::ScrollOffset(data_from_ancestor.elastic_overscroll);
+    node->scroll_offset = gfx::ScrollOffset(elastic_overscroll_);
   } else if (!ScrollParent(layer)) {
     node->scroll_offset = layer->CurrentScrollOffset();
   }
@@ -499,8 +547,7 @@
           PositionConstraint(layer).is_fixed_to_bottom_edge();
       if (node->moved_by_outer_viewport_bounds_delta_x ||
           node->moved_by_outer_viewport_bounds_delta_y) {
-        data_for_children->property_trees->transform_tree
-            .AddNodeAffectedByOuterViewportBoundsDelta(node->id);
+        transform_tree_.AddNodeAffectedByOuterViewportBoundsDelta(node->id);
       }
     }
   }
@@ -510,13 +557,11 @@
 
   if (StickyPositionConstraint(layer).is_sticky) {
     StickyPositionNodeData* sticky_data =
-        data_for_children->property_trees->transform_tree.StickyPositionData(
-            node->id);
+        transform_tree_.StickyPositionData(node->id);
     sticky_data->constraints = StickyPositionConstraint(layer);
     sticky_data->scroll_ancestor = GetScrollParentId(data_from_ancestor, layer);
     ScrollNode* scroll_ancestor =
-        data_for_children->property_trees->scroll_tree.Node(
-            sticky_data->scroll_ancestor);
+        scroll_tree_.Node(sticky_data->scroll_ancestor);
 
     // Position sticky should never attach to the inner viewport since it
     // shouldn't be affected by pinch-zoom. If we did then we'd need setting
@@ -530,10 +575,8 @@
       // need to have their local transform updated when the inner / outer
       // viewport bounds change, but do not unconditionally move by that delta
       // like fixed position nodes.
-      if (scroll_ancestor->scrolls_outer_viewport) {
-        data_for_children->property_trees->transform_tree
-            .AddNodeAffectedByOuterViewportBoundsDelta(node->id);
-      }
+      if (scroll_ancestor->scrolls_outer_viewport)
+        transform_tree_.AddNodeAffectedByOuterViewportBoundsDelta(node->id);
     }
     // Copy the ancestor nodes for later use. These elements are guaranteed to
     // have transform nodes at this point because they are our ancestors (so
@@ -542,22 +585,21 @@
         sticky_data->constraints.nearest_element_shifting_sticky_box;
     if (shifting_sticky_box_element_id) {
       sticky_data->nearest_node_shifting_sticky_box =
-          data_for_children->property_trees->transform_tree
-              .FindNodeFromElementId(shifting_sticky_box_element_id)
+          transform_tree_.FindNodeFromElementId(shifting_sticky_box_element_id)
               ->id;
     }
     ElementId shifting_containing_block_element_id =
         sticky_data->constraints.nearest_element_shifting_containing_block;
     if (shifting_containing_block_element_id) {
       sticky_data->nearest_node_shifting_containing_block =
-          data_for_children->property_trees->transform_tree
+          transform_tree_
               .FindNodeFromElementId(shifting_containing_block_element_id)
               ->id;
     }
   }
 
   node->needs_local_transform_update = true;
-  data_from_ancestor.property_trees->transform_tree.UpdateTransforms(node->id);
+  transform_tree_.UpdateTransforms(node->id);
 
   layer->set_offset_to_transform_parent(gfx::Vector2dF());
 
@@ -857,10 +899,10 @@
 }
 
 template <typename LayerType>
-bool AddEffectNodeIfNeeded(
+bool PropertyTreeBuilderContext<LayerType>::AddEffectNodeIfNeeded(
     const DataForRecursion<LayerType>& data_from_ancestor,
     LayerType* layer,
-    DataForRecursion<LayerType>* data_for_children) {
+    DataForRecursion<LayerType>* data_for_children) const {
   const bool is_root = !Parent(layer);
   const bool has_transparency = EffectiveOpacity(layer) != 1.f;
   const bool has_potential_opacity_animation =
@@ -900,9 +942,8 @@
     return false;
   }
 
-  EffectTree& effect_tree = data_for_children->property_trees->effect_tree;
-  int node_id = effect_tree.Insert(EffectNode(), parent_id);
-  EffectNode* node = effect_tree.back();
+  int node_id = effect_tree_.Insert(EffectNode(), parent_id);
+  EffectNode* node = effect_tree_.back();
 
   node->stable_id = layer->id();
   node->opacity = Opacity(layer);
@@ -933,7 +974,7 @@
 
   if (MaskLayer(layer)) {
     node->mask_layer_id = MaskLayer(layer)->id();
-    effect_tree.AddMaskLayerId(node->mask_layer_id);
+    effect_tree_.AddMaskLayerId(node->mask_layer_id);
   }
 
   if (!is_root) {
@@ -944,8 +985,7 @@
       // In this case, we will create a transform node, so it's safe to use the
       // next available id from the transform tree as this effect node's
       // transform id.
-      node->transform_id =
-          data_from_ancestor.property_trees->transform_tree.next_available_id();
+      node->transform_id = transform_tree_.next_available_id();
     }
     node->clip_id = data_from_ancestor.clip_tree_parent;
   } else {
@@ -969,14 +1009,14 @@
   // For animation subsystem purposes, if this layer has a compositor element
   // id, we build a map from that id to this effect node.
   if (layer->element_id()) {
-    data_for_children->property_trees
-        ->element_id_to_effect_node_index[layer->element_id()] = node_id;
+    property_trees_.element_id_to_effect_node_index[layer->element_id()] =
+        node_id;
   }
 
   std::vector<std::unique_ptr<viz::CopyOutputRequest>> layer_copy_requests;
   TakeCopyRequests(layer, &layer_copy_requests);
   for (auto& it : layer_copy_requests) {
-    effect_tree.AddCopyRequest(node_id, std::move(it));
+    effect_tree_.AddCopyRequest(node_id, std::move(it));
   }
   layer_copy_requests.clear();
 
@@ -1019,10 +1059,10 @@
 }
 
 template <typename LayerType>
-void AddScrollNodeIfNeeded(
+void PropertyTreeBuilderContext<LayerType>::AddScrollNodeIfNeeded(
     const DataForRecursion<LayerType>& data_from_ancestor,
     LayerType* layer,
-    DataForRecursion<LayerType>* data_for_children) {
+    DataForRecursion<LayerType>* data_for_children) const {
   int parent_id = GetScrollParentId(data_from_ancestor, layer);
 
   bool is_root = !Parent(layer);
@@ -1054,10 +1094,8 @@
     node.scrollable = scrollable;
     node.main_thread_scrolling_reasons = main_thread_scrolling_reasons;
     node.non_fast_scrollable_region = layer->non_fast_scrollable_region();
-    node.scrolls_inner_viewport =
-        layer == data_from_ancestor.inner_viewport_scroll_layer;
-    node.scrolls_outer_viewport =
-        layer == data_from_ancestor.outer_viewport_scroll_layer;
+    node.scrolls_inner_viewport = layer == inner_viewport_scroll_layer_;
+    node.scrolls_outer_viewport = layer == outer_viewport_scroll_layer_;
 
     if (node.scrolls_inner_viewport &&
         data_from_ancestor.in_subtree_of_page_scale_layer) {
@@ -1071,12 +1109,10 @@
     node.user_scrollable_horizontal = UserScrollableHorizontal(layer);
     node.user_scrollable_vertical = UserScrollableVertical(layer);
     node.element_id = layer->element_id();
-    node.transform_id =
-        data_for_children->transform_tree_parent->transform_tree_index();
+    node.transform_id = data_for_children->transform_tree_parent;
     node.scroll_boundary_behavior = GetScrollBoundaryBehavior(layer);
 
-    node_id =
-        data_for_children->property_trees->scroll_tree.Insert(node, parent_id);
+    node_id = scroll_tree_.Insert(node, parent_id);
     data_for_children->scroll_tree_parent = node_id;
     data_for_children->main_thread_scrolling_reasons =
         node.main_thread_scrolling_reasons;
@@ -1085,13 +1121,13 @@
     // For animation subsystem purposes, if this layer has a compositor element
     // id, we build a map from that id to this scroll node.
     if (layer->element_id()) {
-      data_for_children->property_trees
-          ->element_id_to_scroll_node_index[layer->element_id()] = node_id;
+      property_trees_.element_id_to_scroll_node_index[layer->element_id()] =
+          node_id;
     }
 
     if (node.scrollable) {
-      data_for_children->property_trees->scroll_tree.SetBaseScrollOffset(
-          layer->element_id(), layer->CurrentScrollOffset());
+      scroll_tree_.SetBaseScrollOffset(layer->element_id(),
+                                       layer->CurrentScrollOffset());
     }
   }
 
@@ -1140,11 +1176,10 @@
                                             LayerImpl* child) {}
 
 template <typename LayerType>
-void BuildPropertyTreesInternal(
+void PropertyTreeBuilderContext<LayerType>::BuildPropertyTreesInternal(
     LayerType* layer,
-    const DataForRecursion<LayerType>& data_from_parent) {
-  layer->set_property_tree_sequence_number(
-      data_from_parent.property_trees->sequence_number);
+    const DataForRecursion<LayerType>& data_from_parent) const {
+  layer->set_property_tree_sequence_number(property_trees_.sequence_number);
 
   DataForRecursion<LayerType> data_for_children(data_from_parent);
 
@@ -1197,7 +1232,7 @@
 
   if (MaskLayer(layer)) {
     MaskLayer(layer)->set_property_tree_sequence_number(
-        data_from_parent.property_trees->sequence_number);
+        property_trees_.sequence_number);
     MaskLayer(layer)->set_offset_to_transform_parent(
         layer->offset_to_transform_parent());
     MaskLayer(layer)->SetTransformTreeIndex(layer->transform_tree_index());
@@ -1226,38 +1261,30 @@
 }
 
 template <typename LayerType>
-void BuildPropertyTreesTopLevelInternal(
+void PropertyTreeBuilderContext<LayerType>::BuildPropertyTrees(
     LayerType* root_layer,
-    const LayerType* page_scale_layer,
-    const LayerType* inner_viewport_scroll_layer,
-    const LayerType* outer_viewport_scroll_layer,
-    const LayerType* overscroll_elasticity_layer,
-    const gfx::Vector2dF& elastic_overscroll,
-    float page_scale_factor,
     float device_scale_factor,
     const gfx::Rect& viewport,
-    const gfx::Transform& device_transform,
-    PropertyTrees* property_trees,
-    SkColor color) {
-  if (!property_trees->needs_rebuild) {
+    SkColor root_background_color) const {
+  if (!property_trees_.needs_rebuild) {
     draw_property_utils::UpdatePageScaleFactor(
-        property_trees, page_scale_layer, page_scale_factor,
-        device_scale_factor, device_transform);
+        &property_trees_, page_scale_layer_, page_scale_factor_,
+        device_scale_factor, device_transform_);
     draw_property_utils::UpdateElasticOverscroll(
-        property_trees, overscroll_elasticity_layer, elastic_overscroll);
-    property_trees->clip_tree.SetViewportClip(gfx::RectF(viewport));
+        &property_trees_, overscroll_elasticity_layer_, elastic_overscroll_);
+    clip_tree_.SetViewportClip(gfx::RectF(viewport));
     float page_scale_factor_for_root =
-        page_scale_layer == root_layer ? page_scale_factor : 1.f;
-    property_trees->transform_tree.SetRootTransformsAndScales(
-        device_scale_factor, page_scale_factor_for_root, device_transform,
+        page_scale_layer_ == root_layer ? page_scale_factor_ : 1.f;
+    transform_tree_.SetRootTransformsAndScales(
+        device_scale_factor, page_scale_factor_for_root, device_transform_,
         root_layer->position());
     return;
   }
 
   DataForRecursion<LayerType> data_for_recursion;
-  data_for_recursion.property_trees = property_trees;
-  data_for_recursion.transform_tree_parent = nullptr;
-  data_for_recursion.transform_fixed_parent = nullptr;
+  data_for_recursion.transform_tree_parent = TransformTree::kInvalidNodeId;
+  data_for_recursion.transform_tree_parent_fixed =
+      TransformTree::kInvalidNodeId;
   data_for_recursion.clip_tree_parent = ClipTree::kRootNodeId;
   data_for_recursion.effect_tree_parent = EffectTree::kInvalidNodeId;
   data_for_recursion.scroll_tree_parent = ScrollTree::kRootNodeId;
@@ -1265,48 +1292,37 @@
       EffectTree::kInvalidNodeId;
   data_for_recursion.closest_ancestor_with_copy_request =
       EffectTree::kInvalidNodeId;
-  data_for_recursion.page_scale_layer = page_scale_layer;
-  data_for_recursion.inner_viewport_scroll_layer = inner_viewport_scroll_layer;
-  data_for_recursion.outer_viewport_scroll_layer = outer_viewport_scroll_layer;
-  data_for_recursion.overscroll_elasticity_layer = overscroll_elasticity_layer;
-  data_for_recursion.elastic_overscroll = elastic_overscroll;
-  data_for_recursion.page_scale_factor = page_scale_factor;
   data_for_recursion.in_subtree_of_page_scale_layer = false;
   data_for_recursion.affected_by_outer_viewport_bounds_delta = false;
   data_for_recursion.should_flatten = false;
-  data_for_recursion.is_hidden = false;
   data_for_recursion.main_thread_scrolling_reasons =
       MainThreadScrollingReason::kNotScrollingOnMain;
   data_for_recursion.scroll_tree_parent_created_by_uninheritable_criteria =
       true;
-  data_for_recursion.device_transform = &device_transform;
-
-  data_for_recursion.property_trees->clear();
   data_for_recursion.compound_transform_since_render_target = gfx::Transform();
   data_for_recursion.animation_axis_aligned_since_render_target = true;
   data_for_recursion.not_axis_aligned_since_last_clip = false;
-  data_for_recursion.property_trees->transform_tree.set_device_scale_factor(
-      device_scale_factor);
-  data_for_recursion.safe_opaque_background_color = color;
+  data_for_recursion.safe_opaque_background_color = root_background_color;
 
+  property_trees_.clear();
+  transform_tree_.set_device_scale_factor(device_scale_factor);
   ClipNode root_clip;
   root_clip.clip_type = ClipNode::ClipType::APPLIES_LOCAL_CLIP;
   root_clip.clip = gfx::RectF(viewport);
   root_clip.transform_id = TransformTree::kRootNodeId;
   data_for_recursion.clip_tree_parent =
-      data_for_recursion.property_trees->clip_tree.Insert(
-          root_clip, ClipTree::kRootNodeId);
+      clip_tree_.Insert(root_clip, ClipTree::kRootNodeId);
 
   BuildPropertyTreesInternal(root_layer, data_for_recursion);
-  property_trees->needs_rebuild = false;
+  property_trees_.needs_rebuild = false;
 
   // The transform tree is kept up to date as it is built, but the
   // combined_clips stored in the clip tree and the screen_space_opacity and
   // is_drawn in the effect tree aren't computed during tree building.
-  property_trees->transform_tree.set_needs_update(false);
-  property_trees->clip_tree.set_needs_update(true);
-  property_trees->effect_tree.set_needs_update(true);
-  property_trees->scroll_tree.set_needs_update(false);
+  transform_tree_.set_needs_update(false);
+  clip_tree_.set_needs_update(true);
+  effect_tree_.set_needs_update(true);
+  scroll_tree_.set_needs_update(false);
 }
 
 #if DCHECK_IS_ON()
@@ -1349,11 +1365,11 @@
     color = SkColorSetA(color, 255);
   if (root_layer->layer_tree_host()->has_copy_request())
     UpdateSubtreeHasCopyRequestRecursive(root_layer);
-  BuildPropertyTreesTopLevelInternal(
-      root_layer, page_scale_layer, inner_viewport_scroll_layer,
+  PropertyTreeBuilderContext<Layer>(
+      page_scale_layer, inner_viewport_scroll_layer,
       outer_viewport_scroll_layer, overscroll_elasticity_layer,
-      elastic_overscroll, page_scale_factor, device_scale_factor, viewport,
-      device_transform, property_trees, color);
+      elastic_overscroll, page_scale_factor, device_transform, *property_trees)
+      .BuildPropertyTrees(root_layer, device_scale_factor, viewport, color);
 #if DCHECK_IS_ON()
   for (auto* layer : *root_layer->layer_tree_host())
     CheckScrollAndClipPointersForLayer(layer);
@@ -1387,11 +1403,12 @@
   if (SkColorGetA(color) != 255)
     color = SkColorSetA(color, 255);
   UpdateSubtreeHasCopyRequestRecursive(root_layer);
-  BuildPropertyTreesTopLevelInternal(
-      root_layer, page_scale_layer, inner_viewport_scroll_layer,
+
+  PropertyTreeBuilderContext<LayerImpl>(
+      page_scale_layer, inner_viewport_scroll_layer,
       outer_viewport_scroll_layer, overscroll_elasticity_layer,
-      elastic_overscroll, page_scale_factor, device_scale_factor, viewport,
-      device_transform, property_trees, color);
+      elastic_overscroll, page_scale_factor, device_transform, *property_trees)
+      .BuildPropertyTrees(root_layer, device_scale_factor, viewport, color);
   property_trees->effect_tree.CreateOrReuseRenderSurfaces(
       &render_surfaces, root_layer->layer_tree_impl());
   property_trees->ResetCachedData();
diff --git a/chrome/VERSION b/chrome/VERSION
index 0787be6..dfe8bb0d7 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=62
 MINOR=0
-BUILD=3200
+BUILD=3201
 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 15a1842..c3fcd40 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -326,7 +326,6 @@
 
 java_cpp_enum("chrome_android_java_enums_srcjar") {
   sources = [
-    "//chrome/browser/android/activity_type_ids.h",
     "//chrome/browser/android/feedback/connectivity_checker.cc",
     "//chrome/browser/android/policy/policy_auditor.cc",
     "//chrome/browser/android/shortcut_info.h",
@@ -616,6 +615,7 @@
       "//components/policy/android:policy_java",
       "//content/public/android:content_java",
       "//content/public/test/android:content_java_test_support",
+      "//net/android:net_java_test_support",
       "//third_party/android_protobuf:protobuf_nano_javalib",
       "//third_party/android_support_test_runner:rules_java",
       "//third_party/android_support_test_runner:runner_java",
@@ -1087,6 +1087,7 @@
     deps = [
       ":chrome_test_vr_java",
     ]
+    additional_apks = [ "//net/android:net_test_support_apk" ]
     proguard_enabled = !is_java_debug
   }
 
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
index b9bc301..536ebb6 100644
--- a/chrome/android/java/AndroidManifest.xml
+++ b/chrome/android/java/AndroidManifest.xml
@@ -766,6 +766,11 @@
             android:exported="false">
         </service>
 
+        <!-- Download service -->
+        <service android:name="org.chromium.chrome.browser.download.DownloadNotificationService"
+            android:exported="false">
+        </service>
+
         <!-- Bookmarks widget -->
         <receiver android:name="com.google.android.apps.chrome.appwidget.bookmarks.BookmarkThumbnailWidgetProvider"
             android:label="@string/bookmark_widget_title">
diff --git a/chrome/android/java/res/drawable-hdpi/bookmarks_signin_promo_card.9.png b/chrome/android/java/res/drawable-hdpi/bookmarks_signin_promo_card.9.png
deleted file mode 100644
index 73e2249..0000000
--- a/chrome/android/java/res/drawable-hdpi/bookmarks_signin_promo_card.9.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-hdpi/infobar_accessibility_events.png b/chrome/android/java/res/drawable-hdpi/infobar_accessibility_events.png
new file mode 100644
index 0000000..c2b5960
--- /dev/null
+++ b/chrome/android/java/res/drawable-hdpi/infobar_accessibility_events.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/bookmarks_signin_promo_card.9.png b/chrome/android/java/res/drawable-mdpi/bookmarks_signin_promo_card.9.png
deleted file mode 100644
index 0d365d0..0000000
--- a/chrome/android/java/res/drawable-mdpi/bookmarks_signin_promo_card.9.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/infobar_accessibility_events.png b/chrome/android/java/res/drawable-mdpi/infobar_accessibility_events.png
new file mode 100644
index 0000000..57c4167
--- /dev/null
+++ b/chrome/android/java/res/drawable-mdpi/infobar_accessibility_events.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/bookmarks_signin_promo_card.9.png b/chrome/android/java/res/drawable-xhdpi/bookmarks_signin_promo_card.9.png
deleted file mode 100644
index f3b2271..0000000
--- a/chrome/android/java/res/drawable-xhdpi/bookmarks_signin_promo_card.9.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/infobar_accessibility_events.png b/chrome/android/java/res/drawable-xhdpi/infobar_accessibility_events.png
new file mode 100644
index 0000000..53a12a1
--- /dev/null
+++ b/chrome/android/java/res/drawable-xhdpi/infobar_accessibility_events.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/bookmarks_signin_promo_card.9.png b/chrome/android/java/res/drawable-xxhdpi/bookmarks_signin_promo_card.9.png
deleted file mode 100644
index c422897..0000000
--- a/chrome/android/java/res/drawable-xxhdpi/bookmarks_signin_promo_card.9.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/infobar_accessibility_events.png b/chrome/android/java/res/drawable-xxhdpi/infobar_accessibility_events.png
new file mode 100644
index 0000000..5a63b68
--- /dev/null
+++ b/chrome/android/java/res/drawable-xxhdpi/infobar_accessibility_events.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/bookmarks_signin_promo_card.9.png b/chrome/android/java/res/drawable-xxxhdpi/bookmarks_signin_promo_card.9.png
deleted file mode 100644
index 88f61fe..0000000
--- a/chrome/android/java/res/drawable-xxxhdpi/bookmarks_signin_promo_card.9.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/infobar_accessibility_events.png b/chrome/android/java/res/drawable-xxxhdpi/infobar_accessibility_events.png
new file mode 100644
index 0000000..8cebecf
--- /dev/null
+++ b/chrome/android/java/res/drawable-xxxhdpi/infobar_accessibility_events.png
Binary files differ
diff --git a/chrome/android/java/res/drawable/content_suggestions_card_modern_background.xml b/chrome/android/java/res/drawable/content_card_modern_background.xml
similarity index 100%
rename from chrome/android/java/res/drawable/content_suggestions_card_modern_background.xml
rename to chrome/android/java/res/drawable/content_card_modern_background.xml
diff --git a/chrome/android/java/res/layout/personalized_signin_promo_view_ntp_content_suggestions.xml b/chrome/android/java/res/layout/personalized_signin_promo_view_ntp_content_suggestions.xml
new file mode 100644
index 0000000..af384cb
--- /dev/null
+++ b/chrome/android/java/res/layout/personalized_signin_promo_view_ntp_content_suggestions.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-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. -->
+
+<org.chromium.chrome.browser.signin.SigninPromoView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/signin_promo_view_container"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="@drawable/ntp_signin_promo_card_single"
+    android:gravity="center_horizontal"
+    android:orientation="vertical"
+    android:paddingBottom="12dp"
+    android:paddingEnd="16dp"
+    android:paddingStart="16dp"
+    android:paddingTop="12dp">
+
+    <include layout="@layout/signin_promo_view_impl"/>
+
+</org.chromium.chrome.browser.signin.SigninPromoView>
\ No newline at end of file
diff --git a/chrome/android/java/res/layout/signin_and_sync_view.xml b/chrome/android/java/res/layout/signin_and_sync_view.xml
index d9bdbeb..29dced95 100644
--- a/chrome/android/java/res/layout/signin_and_sync_view.xml
+++ b/chrome/android/java/res/layout/signin_and_sync_view.xml
@@ -8,23 +8,24 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:orientation="vertical"
-    android:padding="@dimen/signin_and_sync_view_padding" >
+    android:padding="@dimen/signin_and_sync_view_padding"
+    android:layout_marginStart="@dimen/list_item_default_margin"
+    android:layout_marginEnd="@dimen/list_item_default_margin"
+    android:background="@drawable/content_card_modern_background">
 
     <TextView
         android:id="@+id/title"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_marginBottom="8dp"
-        android:textColor="@color/default_text_color"
-        android:textSize="16sp"
-        android:textStyle="bold" />
+        android:textAppearance="@style/BlackTitle1" />
 
     <TextView
         android:id="@+id/description"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:textColor="@color/default_text_color"
-        android:textSize="14sp" />
+        android:textAppearance="@style/BlackBody"
+        android:lineSpacingExtra="6sp" />
 
     <LinearLayout
         android:layout_width="wrap_content"
diff --git a/chrome/android/java/res/layout/signin_promo_view_bookmarks.xml b/chrome/android/java/res/layout/signin_promo_view_bookmarks.xml
index 4329d2b..a85af5a 100644
--- a/chrome/android/java/res/layout/signin_promo_view_bookmarks.xml
+++ b/chrome/android/java/res/layout/signin_promo_view_bookmarks.xml
@@ -9,7 +9,7 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:layout_margin="16dp"
-    android:background="@drawable/bookmarks_signin_promo_card"
+    android:background="@drawable/content_card_modern_background"
     android:gravity="center_horizontal"
     android:orientation="vertical"
     android:paddingBottom="12dp"
diff --git a/chrome/android/java/res/values-v17/styles.xml b/chrome/android/java/res/values-v17/styles.xml
index c6fe783..45f0e3ca 100644
--- a/chrome/android/java/res/values-v17/styles.xml
+++ b/chrome/android/java/res/values-v17/styles.xml
@@ -736,7 +736,7 @@
     <!-- Content and Site Suggestions -->
     <style name="SuggestionCardModern">
         <item name="android:layout_marginBottom">@dimen/content_suggestions_card_modern_margin</item>
-        <item name="android:background">@drawable/content_suggestions_card_modern_background</item>
+        <item name="android:background">@drawable/content_card_modern_background</item>
         <item name="android:foreground">@drawable/button_borderless_compat</item>
     </style>
     <style name="SuggestionCardTitleModern" parent="BlackTitle1">
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 755d158..53bf2e98 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -1912,7 +1912,6 @@
             if (currentTab.canGoForward()) {
                 currentTab.goForward();
                 RecordUserAction.record("MobileMenuForward");
-                RecordUserAction.record("MobileTabClobbered");
             }
         } else if (id == R.id.bookmark_this_page_id) {
             addOrEditBookmark(currentTab);
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 18a98c40..9888f2c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -1154,7 +1154,6 @@
                     if (tabToBeClobbered != null) {
                         TabModelUtils.setIndex(tabModel, tabToBeClobberedIndex);
                         tabToBeClobbered.reload();
-                        RecordUserAction.record("MobileTabClobbered");
                     } else {
                         launchIntent(url, referer, headers, externalAppId, true, intent);
                     }
@@ -1206,7 +1205,6 @@
                                     referer, IntentHandler.getReferrerPolicyFromIntent(intent)));
                         }
                         currentTab.loadUrl(loadUrlParams);
-                        RecordUserAction.record("MobileTabClobbered");
                     } else {
                         launchIntent(url, referer, headers, externalAppId, true, intent);
                     }
@@ -1706,7 +1704,6 @@
 
         if (getToolbarManager().back()) {
             recordBackPressedUma("Navigating backward", BACK_PRESSED_NAVIGATED_BACK);
-            RecordUserAction.record("MobileTabClobbered");
             return true;
         }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkPromoHeader.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkPromoHeader.java
index a731486..190886d4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkPromoHeader.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkPromoHeader.java
@@ -14,7 +14,6 @@
 import android.view.View;
 import android.view.ViewGroup;
 
-import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.metrics.RecordUserAction;
@@ -28,7 +27,6 @@
 import org.chromium.chrome.browser.signin.SigninManager.SignInStateObserver;
 import org.chromium.chrome.browser.signin.SigninPromoController;
 import org.chromium.chrome.browser.signin.SigninPromoView;
-import org.chromium.chrome.browser.widget.displaystyle.MarginResizer;
 import org.chromium.components.signin.AccountManagerFacade;
 import org.chromium.components.signin.AccountsChangeObserver;
 import org.chromium.components.signin.ChromeSigninController;
@@ -165,15 +163,6 @@
         SigninAndSyncView view =
                 SigninAndSyncView.create(parent, listener, SigninAccessPoint.BOOKMARK_MANAGER);
 
-        // A MarginResizer is used to apply margins in regular and wide display modes. Remove
-        // the view's lateral padding so that margins can be used instead.
-        ApiCompatibilityUtils.setPaddingRelative(
-                view, 0, view.getPaddingTop(), 0, view.getPaddingBottom());
-        MarginResizer.createAndAttach(view,
-                mBookmarkDelegate.getSelectableListLayout().getUiConfig(),
-                parent.getResources().getDimensionPixelSize(R.dimen.signin_and_sync_view_padding),
-                0);
-
         // ViewHolder is abstract and it cannot be instantiated directly.
         return new ViewHolder(view) {};
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
index ec93ec62..24feb40 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
@@ -11,6 +11,7 @@
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
 import android.view.ViewTreeObserver.OnGlobalFocusChangeListener;
+import android.view.textclassifier.TextClassifier;
 
 import org.chromium.base.ObserverList;
 import org.chromium.base.SysUtils;
@@ -1237,15 +1238,15 @@
     public void cancelAllRequests() {}
 
     @Override
-    public void setTextClassifier(Object textClassifier) {}
+    public void setTextClassifier(TextClassifier textClassifier) {}
 
     @Override
-    public Object getTextClassifier() {
+    public TextClassifier getTextClassifier() {
         return null;
     }
 
     @Override
-    public Object getCustomTextClassifier() {
+    public TextClassifier getCustomTextClassifier() {
         return null;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java
index 8e4b92d..a9174b7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java
@@ -148,8 +148,10 @@
                 MultiWindowUtils.getInstance().shouldRunInLegacyMultiInstanceMode(this);
         mIntentHandler = new IntentHandler(this, getPackageName());
         mIsCustomTabIntent = isCustomTabIntent(getIntent());
+        boolean isVrIntent = VrIntentUtils.isVrIntent(getIntent());
         // If the intent was created by Reader Mode, ignore herb and custom tab information.
-        if (!mIsCustomTabIntent && !ReaderModeManager.isReaderModeCreatedIntent(getIntent())) {
+        if (!mIsCustomTabIntent && !ReaderModeManager.isReaderModeCreatedIntent(getIntent())
+                && !isVrIntent) {
             mIsHerbIntent = isHerbIntent();
             mIsCustomTabIntent = mIsHerbIntent;
         }
@@ -203,9 +205,7 @@
         // Check if we should launch the ChromeTabbedActivity.
         if (!mIsCustomTabIntent && !FeatureUtilities.isDocumentMode(this)) {
             Bundle options = null;
-            if (VrIntentUtils.isVrIntent(getIntent())) {
-                options = VrIntentUtils.getVrIntentOptions(this);
-            }
+            if (isVrIntent) options = VrIntentUtils.getVrIntentOptions(this);
             launchTabbedMode(options);
             finish();
             return;
@@ -317,9 +317,10 @@
      * @return Whether the intent is for launching a Custom Tab.
      */
     public static boolean isCustomTabIntent(Intent intent) {
-        if (intent == null || CustomTabsIntent.shouldAlwaysUseBrowserUI(intent)
-                || (!intent.hasExtra(CustomTabsIntent.EXTRA_SESSION)
-                           && !VrIntentUtils.isCustomTabVrIntent(intent))) {
+        if (intent == null) return false;
+        if ((CustomTabsIntent.shouldAlwaysUseBrowserUI(intent)
+                    || !intent.hasExtra(CustomTabsIntent.EXTRA_SESSION))
+                && !VrIntentUtils.isCustomTabVrIntent(intent)) {
             return false;
         }
         return IntentHandler.getUrlFromIntent(intent) != null;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java
index 18d2fa1..62bbdad 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java
@@ -6,13 +6,13 @@
 
 import static android.app.DownloadManager.ACTION_NOTIFICATION_CLICKED;
 
-import static org.chromium.chrome.browser.download.DownloadNotificationService.ACTION_DOWNLOAD_CANCEL;
-import static org.chromium.chrome.browser.download.DownloadNotificationService.ACTION_DOWNLOAD_OPEN;
-import static org.chromium.chrome.browser.download.DownloadNotificationService.ACTION_DOWNLOAD_PAUSE;
-import static org.chromium.chrome.browser.download.DownloadNotificationService.ACTION_DOWNLOAD_RESUME;
-import static org.chromium.chrome.browser.download.DownloadNotificationService.EXTRA_DOWNLOAD_CONTENTID_ID;
-import static org.chromium.chrome.browser.download.DownloadNotificationService.EXTRA_DOWNLOAD_CONTENTID_NAMESPACE;
-import static org.chromium.chrome.browser.download.DownloadNotificationService.EXTRA_IS_OFF_THE_RECORD;
+import static org.chromium.chrome.browser.download.DownloadNotificationService2.ACTION_DOWNLOAD_CANCEL;
+import static org.chromium.chrome.browser.download.DownloadNotificationService2.ACTION_DOWNLOAD_OPEN;
+import static org.chromium.chrome.browser.download.DownloadNotificationService2.ACTION_DOWNLOAD_PAUSE;
+import static org.chromium.chrome.browser.download.DownloadNotificationService2.ACTION_DOWNLOAD_RESUME;
+import static org.chromium.chrome.browser.download.DownloadNotificationService2.EXTRA_DOWNLOAD_CONTENTID_ID;
+import static org.chromium.chrome.browser.download.DownloadNotificationService2.EXTRA_DOWNLOAD_CONTENTID_NAMESPACE;
+import static org.chromium.chrome.browser.download.DownloadNotificationService2.EXTRA_IS_OFF_THE_RECORD;
 
 import android.app.DownloadManager;
 import android.app.Service;
@@ -53,7 +53,7 @@
             DownloadSharedPreferenceHelper.getInstance();
 
     private final Context mApplicationContext;
-    private final DownloadNotificationService mDownloadNotificationService;
+    private final DownloadNotificationService2 mDownloadNotificationService;
     private final Handler mHandler = new Handler();
     private final Runnable mStopSelfRunnable = new Runnable() {
         @Override
@@ -64,7 +64,7 @@
 
     public DownloadBroadcastManager() {
         mApplicationContext = ContextUtils.getApplicationContext();
-        mDownloadNotificationService = DownloadNotificationService.getInstance();
+        mDownloadNotificationService = DownloadNotificationService2.getInstance();
     }
 
     // The service is only explicitly started in the resume case.
@@ -295,11 +295,11 @@
         }
 
         String downloadFilename = IntentUtils.safeGetStringExtra(
-                intent, DownloadNotificationService.EXTRA_DOWNLOAD_FILE_PATH);
+                intent, DownloadNotificationService2.EXTRA_DOWNLOAD_FILE_PATH);
         boolean isSupportedMimeType = IntentUtils.safeGetBooleanExtra(
-                intent, DownloadNotificationService.EXTRA_IS_SUPPORTED_MIME_TYPE, false);
+                intent, DownloadNotificationService2.EXTRA_IS_SUPPORTED_MIME_TYPE, false);
         boolean isOffTheRecord = IntentUtils.safeGetBooleanExtra(
-                intent, DownloadNotificationService.EXTRA_IS_OFF_THE_RECORD, false);
+                intent, DownloadNotificationService2.EXTRA_IS_OFF_THE_RECORD, false);
         String originalUrl = IntentUtils.safeGetStringExtra(intent, Intent.EXTRA_ORIGINATING_URI);
         String referrer = IntentUtils.safeGetStringExtra(intent, Intent.EXTRA_REFERRER);
         DownloadManagerService.openDownloadedContent(context, downloadFilename, isSupportedMimeType,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastReceiver.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastReceiver.java
new file mode 100644
index 0000000..74537116
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastReceiver.java
@@ -0,0 +1,92 @@
+// 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.
+
+package org.chromium.chrome.browser.download;
+
+import android.app.DownloadManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+
+import org.chromium.chrome.browser.notifications.NotificationConstants;
+import org.chromium.chrome.browser.util.IntentUtils;
+import org.chromium.components.offline_items_collection.ContentId;
+
+/**
+ * This {@link BroadcastReceiver} handles clicks to download notifications and their action buttons.
+ * Clicking on an in-progress or failed download will open the download manager. Clicking on
+ * a complete, successful download will open the file. Clicking on the resume button of a paused
+ * download will relaunch the browser process and try to resume the download from where it is
+ * stopped.
+ */
+public class DownloadBroadcastReceiver extends BroadcastReceiver {
+    @Override
+    public void onReceive(final Context context, Intent intent) {
+        String action = intent.getAction();
+        switch (action) {
+            case DownloadManager.ACTION_NOTIFICATION_CLICKED:
+                openDownload(context, intent);
+                break;
+            case DownloadNotificationService.ACTION_DOWNLOAD_RESUME:
+            case DownloadNotificationService.ACTION_DOWNLOAD_CANCEL:
+            case DownloadNotificationService.ACTION_DOWNLOAD_PAUSE:
+            case DownloadNotificationService.ACTION_DOWNLOAD_OPEN:
+            case DownloadNotificationService.ACTION_DOWNLOAD_UPDATE_SUMMARY_ICON:
+                performDownloadOperation(context, intent);
+                break;
+            default:
+                break;
+        }
+    }
+
+    /**
+     * Called to open a particular download item.  Falls back to opening Download Home.
+     * @param context Context of the receiver.
+     * @param intent Intent from the android DownloadManager.
+     */
+    private void openDownload(final Context context, Intent intent) {
+        int notificationId = IntentUtils.safeGetIntExtra(
+                intent, NotificationConstants.EXTRA_NOTIFICATION_ID, -1);
+        DownloadNotificationService.hideDanglingSummaryNotification(context, notificationId);
+
+        long ids[] =
+                intent.getLongArrayExtra(DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS);
+        if (ids == null || ids.length == 0) {
+            DownloadManagerService.openDownloadsPage(context);
+            return;
+        }
+
+        long id = ids[0];
+        Uri uri = DownloadManagerDelegate.getContentUriFromDownloadManager(context, id);
+        if (uri == null) {
+            DownloadManagerService.openDownloadsPage(context);
+            return;
+        }
+
+        String downloadFilename = IntentUtils.safeGetStringExtra(
+                intent, DownloadNotificationService.EXTRA_DOWNLOAD_FILE_PATH);
+        boolean isSupportedMimeType = IntentUtils.safeGetBooleanExtra(
+                intent, DownloadNotificationService.EXTRA_IS_SUPPORTED_MIME_TYPE, false);
+        boolean isOffTheRecord = IntentUtils.safeGetBooleanExtra(
+                intent, DownloadNotificationService.EXTRA_IS_OFF_THE_RECORD, false);
+        String originalUrl = IntentUtils.safeGetStringExtra(intent, Intent.EXTRA_ORIGINATING_URI);
+        String referrer = IntentUtils.safeGetStringExtra(intent, Intent.EXTRA_REFERRER);
+        ContentId contentId = DownloadNotificationService.getContentIdFromIntent(intent);
+        DownloadManagerService.openDownloadedContent(context, downloadFilename, isSupportedMimeType,
+                isOffTheRecord, contentId.id, id, originalUrl, referrer);
+    }
+
+    /**
+     * Called to perform a download operation. This will call the DownloadNotificationService
+     * to start the browser process asynchronously, and resume or cancel the download afterwards.
+     * @param context Context of the receiver.
+     * @param intent Intent retrieved from the notification.
+     */
+    private void performDownloadOperation(final Context context, Intent intent) {
+        if (DownloadNotificationService.isDownloadOperationIntent(intent)) {
+            DownloadNotificationService.startDownloadNotificationService(context, intent);
+        }
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
index 7503405..7b398e59 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
@@ -4,8 +4,6 @@
 
 package org.chromium.chrome.browser.download;
 
-import static org.chromium.chrome.browser.download.DownloadNotificationFactory.buildActionIntent;
-
 import android.app.DownloadManager;
 import android.content.ActivityNotFoundException;
 import android.content.Context;
@@ -358,7 +356,10 @@
      * Called when browser activity is launched. For background resumption and cancellation, this
      * will not be called.
      */
-    public void onActivityLaunched() {}
+    public void onActivityLaunched() {
+        // TODO(jming): Remove this after M-62.
+        DownloadNotificationService.clearResumptionAttemptLeft();
+    }
 
     /**
      * Broadcast that a download was successful.
@@ -1368,10 +1369,10 @@
      */
     @Override
     public void broadcastDownloadAction(DownloadItem downloadItem, String action) {
-        Intent intent = buildActionIntent(mContext, action,
+        Intent intent = DownloadNotificationService.buildActionIntent(mContext, action,
                 LegacyHelpers.buildLegacyContentId(false, downloadItem.getId()),
                 downloadItem.getDownloadInfo().isOffTheRecord());
-        mContext.sendBroadcast(intent);
+        mContext.startService(intent);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationFactory.java
index 7301014..affdf1f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationFactory.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationFactory.java
@@ -7,16 +7,16 @@
 import static android.app.DownloadManager.ACTION_NOTIFICATION_CLICKED;
 import static android.app.DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS;
 
-import static org.chromium.chrome.browser.download.DownloadNotificationService.ACTION_DOWNLOAD_CANCEL;
-import static org.chromium.chrome.browser.download.DownloadNotificationService.ACTION_DOWNLOAD_OPEN;
-import static org.chromium.chrome.browser.download.DownloadNotificationService.ACTION_DOWNLOAD_PAUSE;
-import static org.chromium.chrome.browser.download.DownloadNotificationService.ACTION_DOWNLOAD_RESUME;
-import static org.chromium.chrome.browser.download.DownloadNotificationService.EXTRA_DOWNLOAD_CONTENTID_ID;
-import static org.chromium.chrome.browser.download.DownloadNotificationService.EXTRA_DOWNLOAD_CONTENTID_NAMESPACE;
-import static org.chromium.chrome.browser.download.DownloadNotificationService.EXTRA_DOWNLOAD_FILE_PATH;
-import static org.chromium.chrome.browser.download.DownloadNotificationService.EXTRA_IS_OFF_THE_RECORD;
-import static org.chromium.chrome.browser.download.DownloadNotificationService.EXTRA_IS_SUPPORTED_MIME_TYPE;
-import static org.chromium.chrome.browser.download.DownloadNotificationService.EXTRA_NOTIFICATION_BUNDLE_ICON_ID;
+import static org.chromium.chrome.browser.download.DownloadNotificationService2.ACTION_DOWNLOAD_CANCEL;
+import static org.chromium.chrome.browser.download.DownloadNotificationService2.ACTION_DOWNLOAD_OPEN;
+import static org.chromium.chrome.browser.download.DownloadNotificationService2.ACTION_DOWNLOAD_PAUSE;
+import static org.chromium.chrome.browser.download.DownloadNotificationService2.ACTION_DOWNLOAD_RESUME;
+import static org.chromium.chrome.browser.download.DownloadNotificationService2.EXTRA_DOWNLOAD_CONTENTID_ID;
+import static org.chromium.chrome.browser.download.DownloadNotificationService2.EXTRA_DOWNLOAD_CONTENTID_NAMESPACE;
+import static org.chromium.chrome.browser.download.DownloadNotificationService2.EXTRA_DOWNLOAD_FILE_PATH;
+import static org.chromium.chrome.browser.download.DownloadNotificationService2.EXTRA_IS_OFF_THE_RECORD;
+import static org.chromium.chrome.browser.download.DownloadNotificationService2.EXTRA_IS_SUPPORTED_MIME_TYPE;
+import static org.chromium.chrome.browser.download.DownloadNotificationService2.EXTRA_NOTIFICATION_BUNDLE_ICON_ID;
 
 import android.app.Notification;
 import android.app.PendingIntent;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java
index f33a964..71e5886b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java
@@ -4,8 +4,14 @@
 
 package org.chromium.chrome.browser.download;
 
+import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
+import android.app.DownloadManager;
 import android.app.Notification;
 import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
@@ -16,33 +22,66 @@
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.graphics.drawable.shapes.OvalShape;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.service.notification.StatusBarNotification;
 import android.text.TextUtils;
+import android.util.Pair;
 
 import org.chromium.base.ApiCompatibilityUtils;
+import org.chromium.base.ApplicationStatus;
+import org.chromium.base.BuildInfo;
 import org.chromium.base.ContextUtils;
+import org.chromium.base.Log;
+import org.chromium.base.ObserverList;
 import org.chromium.base.VisibleForTesting;
+import org.chromium.base.library_loader.LibraryProcessType;
+import org.chromium.base.library_loader.ProcessInitException;
+import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.AppHooks;
+import org.chromium.chrome.browser.ChromeApplication;
+import org.chromium.chrome.browser.download.items.OfflineContentAggregatorNotificationBridgeUiFactory;
+import org.chromium.chrome.browser.init.BrowserParts;
+import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
+import org.chromium.chrome.browser.init.EmptyBrowserParts;
+import org.chromium.chrome.browser.notifications.ChromeNotificationBuilder;
+import org.chromium.chrome.browser.notifications.NotificationBuilderFactory;
+import org.chromium.chrome.browser.notifications.NotificationConstants;
 import org.chromium.chrome.browser.notifications.NotificationUmaTracker;
 import org.chromium.chrome.browser.notifications.channels.ChannelDefinitions;
+import org.chromium.chrome.browser.offlinepages.downloads.OfflinePageDownloadBridge;
+import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.util.IntentUtils;
 import org.chromium.components.offline_items_collection.ContentId;
 import org.chromium.components.offline_items_collection.LegacyHelpers;
 import org.chromium.components.offline_items_collection.OfflineItem.Progress;
+import org.chromium.content.browser.BrowserStartupController;
 
 import java.util.ArrayList;
 import java.util.List;
 
 /**
- * Central director for updates related to downloads and notifications.
- *  - Receive updates about downloads through SystemDownloadNotifier (notifyDownloadPaused, etc).
- *  - Create notifications for downloads using DownloadNotificationFactory.
- *  - Update DownloadForegroundServiceManager about downloads, allowing it to start/stop service.
+ * Service responsible for creating and updating download notifications even after
+ * Chrome gets killed.
+ *
+ * On O and above, this service will receive {@link Service#startForeground(int, Notification)}
+ * calls when containing active downloads.  The foreground notification will be the summary
+ * notification generated by {@link DownloadNotificationService#buildSummaryNotification(Context)}.
+ * The service will receive a {@link Service#stopForeground(boolean)} call when all active downloads
+ * are paused.  The summary notification will be hidden when there are no other notifications in the
+ * {@link NotificationConstants#GROUP_DOWNLOADS} group.  This gets checked after every notification
+ * gets removed from the {@link NotificationManager}.
  */
-public class DownloadNotificationService {
+public class DownloadNotificationService extends Service {
     static final String EXTRA_DOWNLOAD_CONTENTID_ID =
             "org.chromium.chrome.browser.download.DownloadContentId_Id";
     static final String EXTRA_DOWNLOAD_CONTENTID_NAMESPACE =
             "org.chromium.chrome.browser.download.DownloadContentId_Namespace";
     static final String EXTRA_DOWNLOAD_FILE_PATH = "DownloadFilePath";
+    static final String EXTRA_NOTIFICATION_DISMISSED = "NotificationDismissed";
     static final String EXTRA_IS_SUPPORTED_MIME_TYPE = "IsSupportedMimeType";
     static final String EXTRA_IS_OFF_THE_RECORD =
             "org.chromium.chrome.browser.download.IS_OFF_THE_RECORD";
@@ -53,67 +92,317 @@
             "org.chromium.chrome.browser.download.DOWNLOAD_PAUSE";
     public static final String ACTION_DOWNLOAD_RESUME =
             "org.chromium.chrome.browser.download.DOWNLOAD_RESUME";
+    static final String ACTION_DOWNLOAD_RESUME_ALL =
+            "org.chromium.chrome.browser.download.DOWNLOAD_RESUME_ALL";
     public static final String ACTION_DOWNLOAD_OPEN =
             "org.chromium.chrome.browser.download.DOWNLOAD_OPEN";
+    public static final String ACTION_DOWNLOAD_UPDATE_SUMMARY_ICON =
+            "org.chromium.chrome.browser.download.DOWNLOAD_UPDATE_SUMMARY_ICON";
+    public static final String ACTION_DOWNLOAD_FAIL_SAFE =
+            "org.chromium.chrome.browser.download.ACTION_SUMMARY_FAIL_SAFE";
 
-    public static final String EXTRA_NOTIFICATION_BUNDLE_ICON_ID =
-            "Chrome.NotificationBundleIconIdExtra";
+    static final String NOTIFICATION_NAMESPACE = "DownloadNotificationService";
+    private static final String TAG = "DownloadNotification";
+    // Limit file name to 25 characters. TODO(qinmin): use different limit for different devices?
+    private static final int MAX_FILE_NAME_LENGTH = 25;
+
     /** Notification Id starting value, to avoid conflicts from IDs used in prior versions. */
-    private static final int STARTING_NOTIFICATION_ID = 1000000;
 
+    private static final String EXTRA_NOTIFICATION_BUNDLE_ICON_ID =
+            "Chrome.NotificationBundleIconIdExtra";
+    private static final int STARTING_NOTIFICATION_ID = 1000000;
+    private static final int MAX_RESUMPTION_ATTEMPT_LEFT = 5;
+
+    private static final String KEY_AUTO_RESUMPTION_ATTEMPT_LEFT = "ResumptionAttemptLeft";
     private static final String KEY_NEXT_DOWNLOAD_NOTIFICATION_ID = "NextDownloadNotificationId";
 
-    @VisibleForTesting
-    final List<ContentId> mDownloadsInProgress = new ArrayList<ContentId>();
+    /**
+     * An Observer interface that allows other classes to know when this class is canceling
+     * downloads.
+     */
+    public interface Observer {
+        /**
+         * Called when a download was canceled from the notification.  The implementer is not
+         * responsible for canceling the actual download (that should be triggered internally from
+         * this class).  The implementer is responsible for using this to do their own tracking
+         * related to which downloads might be active in this service.  File downloads don't trigger
+         * a cancel event when they are told to cancel downloads, so classes might have no idea that
+         * a download stopped otherwise.
+         * @param id The {@link ContentId} of the download that was canceled.
+         */
+        void onDownloadCanceled(ContentId id);
+    }
+
+    private final ObserverList<Observer> mObservers = new ObserverList<>();
+    private final IBinder mBinder = new LocalBinder();
+    private final List<ContentId> mDownloadsInProgress = new ArrayList<ContentId>();
 
     private NotificationManager mNotificationManager;
     private SharedPreferences mSharedPrefs;
+    private Context mContext;
     private int mNextNotificationId;
+    private int mNumAutoResumptionAttemptLeft;
     private Bitmap mDownloadSuccessLargeIcon;
     private DownloadSharedPreferenceHelper mDownloadSharedPreferenceHelper;
-    private DownloadForegroundServiceManager mDownloadForegroundServiceManager;
 
-    private static class LazyHolder {
-        private static final DownloadNotificationService INSTANCE =
-                new DownloadNotificationService();
+    /**
+     * @return Whether or not this service should be made a foreground service if there are active
+     * downloads.
+     */
+    @VisibleForTesting
+    static boolean useForegroundService() {
+        return BuildInfo.isAtLeastO();
     }
 
     /**
-     * Creates DownloadNotificationService.
+     * Checks to see if the summary notification is alone and, if so, hides it.  If the summary
+     * notification thinks it's in the foreground, this will start the service with the goal of
+     * shutting it down.  That is because if the service is in the foreground it's not possible to
+     * stop it through the notification manager.
+     * @param removedNotificationId The id of the notification that was just removed or {@code -1}
+     *                              if this does not apply.
      */
-    public static DownloadNotificationService getInstance() {
-        return LazyHolder.INSTANCE;
+    @TargetApi(Build.VERSION_CODES.M)
+    public static void hideDanglingSummaryNotification(Context context, int removedNotificationId) {
+        if (!useForegroundService()) return;
+
+        NotificationManager manager =
+                (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+        if (hasDownloadNotifications(manager, removedNotificationId)) return;
+
+        StatusBarNotification summary = getSummaryNotification(manager);
+        if (summary == null) return;
+
+        boolean isForeground =
+                (summary.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE) != 0;
+
+        if (BrowserStartupController.get(LibraryProcessType.PROCESS_BROWSER)
+                        .isStartupSuccessfullyCompleted()) {
+            RecordHistogram.recordBooleanHistogram(
+                    "MobileDownload.Notification.FixingSummaryLeak", isForeground);
+        }
+
+        if (isForeground) {
+            // If it is a foreground notification, we are in a bad state.  We don't have any
+            // other download notifications, but we can't close the summary.  Try to start
+            // up the service and quit through that path?
+            startDownloadNotificationService(context, new Intent(ACTION_DOWNLOAD_FAIL_SAFE));
+        } else {
+            manager.cancel(NotificationConstants.NOTIFICATION_ID_DOWNLOAD_SUMMARY);
+        }
     }
 
-    @VisibleForTesting
-    DownloadNotificationService() {
-        mNotificationManager =
-                (NotificationManager) ContextUtils.getApplicationContext().getSystemService(
-                        Context.NOTIFICATION_SERVICE);
-        mSharedPrefs = ContextUtils.getAppSharedPreferences();
-        mDownloadSharedPreferenceHelper = DownloadSharedPreferenceHelper.getInstance();
-        mNextNotificationId = mSharedPrefs.getInt(
-                KEY_NEXT_DOWNLOAD_NOTIFICATION_ID, STARTING_NOTIFICATION_ID);
-        mDownloadForegroundServiceManager = new DownloadForegroundServiceManager();
+    /**
+     * Start this service with a summary {@link Notification}.  This will start the service in the
+     * foreground.
+     * @param context The context used to build the notification and to start the service.
+     * @param source The {@link Intent} that should be used to build on to start the service.
+     */
+    public static void startDownloadNotificationService(Context context, Intent source) {
+        Intent intent = source != null ? new Intent(source) : new Intent();
+        intent.setComponent(new ComponentName(context, DownloadNotificationService.class));
+
+        if (useForegroundService()) {
+            NotificationManager manager =
+                    (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+            // Attempt to update the notification summary icon without starting the service.
+            if (ACTION_DOWNLOAD_UPDATE_SUMMARY_ICON.equals(intent.getAction())) {
+                // updateSummaryIcon should be a noop if the notification isn't showing or if the
+                // icon won't change anyway.
+                updateSummaryIcon(context, manager, -1, null);
+                return;
+            }
+
+            AppHooks.get().startForegroundService(intent);
+        } else {
+            context.startService(intent);
+        }
     }
 
-    @VisibleForTesting
-    void setDownloadForegroundServiceManager(
-            DownloadForegroundServiceManager downloadForegroundServiceManager) {
-        mDownloadForegroundServiceManager = downloadForegroundServiceManager;
+    /**
+     * Updates the notification summary with a new icon, if necessary.
+     * @param removedNotificationId The id of a notification that is currently closing and should be
+     *                              ignored.  -1 if no notifications are being closed.
+     * @param addedNotification     A {@link Pair} of <id, Notification> of a notification that is
+     *                              currently being added and should be used in addition to or in
+     *                              place of the existing icons.
+     */
+    private static void updateSummaryIcon(Context context, NotificationManager manager,
+            int removedNotificationId, Pair<Integer, Notification> addedNotification) {
+        if (!useForegroundService()) return;
+
+        Pair<Boolean, Integer> icon =
+                getSummaryIcon(context, manager, removedNotificationId, addedNotification);
+        if (!icon.first || !hasDownloadNotifications(manager, removedNotificationId)) return;
+
+        manager.notify(NotificationConstants.NOTIFICATION_ID_DOWNLOAD_SUMMARY,
+                buildSummaryNotificationWithIcon(context, icon.second));
     }
 
-    // TODO(jming): Figure out resumption logic (http://crbug.com/755771)
-    //  - onDestroy/rescheduleDownloads/updateNotificationsForShutdown
-    //  - onTaskRemoved/cancelOffTheRecordDownloads
-    //  - onStartCommand/null Intent
-    //  - updateResumptionAttemptLeft / etc.
+    /**
+     * Returns whether or not there are any download notifications showing that aren't the summary
+     * notification.
+     * @param notificationIdToIgnore If not -1, the id of a notification to ignore and
+     *                               assume is closing or about to be closed.
+     * @return Whether or not there are valid download notifications currently visible.
+     */
+    @TargetApi(Build.VERSION_CODES.M)
+    private static boolean hasDownloadNotifications(
+            NotificationManager manager, int notificationIdToIgnore) {
+        if (!useForegroundService()) return false;
+
+        StatusBarNotification[] notifications = manager.getActiveNotifications();
+        for (StatusBarNotification notification : notifications) {
+            boolean isDownloadsGroup = TextUtils.equals(notification.getNotification().getGroup(),
+                    NotificationConstants.GROUP_DOWNLOADS);
+            boolean isSummaryNotification =
+                    notification.getId() == NotificationConstants.NOTIFICATION_ID_DOWNLOAD_SUMMARY;
+            boolean isIgnoredNotification =
+                    notificationIdToIgnore != -1 && notificationIdToIgnore == notification.getId();
+            if (isDownloadsGroup && !isSummaryNotification && !isIgnoredNotification) return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Calculates the suggested icon for the summary notification based on the other notifications
+     * currently showing.
+     * @param context A context to use to query Android-specific information (NotificationManager).
+     * @param removedNotificationId The id of a notification that is currently closing and should be
+     *                              ignored.  -1 if no notifications are being closed.
+     * @param addedNotification     A {@link Pair} of <id, Notification> of a notification that is
+     *                              currently being added and should be used in addition to or in
+     *                              place of the existing icons.
+     * @return                      A {@link Pair} that represents both whether or not the new icon
+     *                              is different from the old one and the icon id itself.
+     */
+    @TargetApi(Build.VERSION_CODES.M)
+    private static Pair<Boolean, Integer> getSummaryIcon(Context context,
+            NotificationManager manager, int removedNotificationId,
+            Pair<Integer, Notification> addedNotification) {
+        if (!useForegroundService()) return new Pair<Boolean, Integer>(false, -1);
+        boolean progress = false;
+        boolean paused = false;
+        boolean pending = false;
+        boolean completed = false;
+        boolean failed = false;
+
+        final int progressIcon = android.R.drawable.stat_sys_download;
+        final int pausedIcon = R.drawable.ic_download_pause;
+        final int pendingIcon = R.drawable.ic_download_pending;
+        final int completedIcon = R.drawable.offline_pin;
+        final int failedIcon = android.R.drawable.stat_sys_download_done;
+
+        StatusBarNotification[] notifications = manager.getActiveNotifications();
+
+        int oldIcon = -1;
+        for (StatusBarNotification notification : notifications) {
+            boolean isDownloadsGroup = TextUtils.equals(notification.getNotification().getGroup(),
+                    NotificationConstants.GROUP_DOWNLOADS);
+            if (!isDownloadsGroup) continue;
+            if (notification.getId() == removedNotificationId) continue;
+
+            boolean isSummaryNotification =
+                    notification.getId() == NotificationConstants.NOTIFICATION_ID_DOWNLOAD_SUMMARY;
+
+            if (addedNotification != null && addedNotification.first == notification.getId()) {
+                continue;
+            }
+
+            int icon =
+                    notification.getNotification().extras.getInt(EXTRA_NOTIFICATION_BUNDLE_ICON_ID);
+            if (isSummaryNotification) {
+                oldIcon = icon;
+                continue;
+            }
+
+            progress |= icon == progressIcon;
+            paused |= icon == pausedIcon;
+            pending |= icon == pendingIcon;
+            completed |= icon == completedIcon;
+            failed |= icon == failedIcon;
+        }
+
+        if (addedNotification != null) {
+            int icon = addedNotification.second.extras.getInt(EXTRA_NOTIFICATION_BUNDLE_ICON_ID);
+
+            progress |= icon == progressIcon;
+            paused |= icon == pausedIcon;
+            pending |= icon == pendingIcon;
+            completed |= icon == completedIcon;
+            failed |= icon == failedIcon;
+        }
+
+        int newIcon = android.R.drawable.stat_sys_download_done;
+        if (progress) {
+            newIcon = android.R.drawable.stat_sys_download;
+        } else if (pending) {
+            newIcon = R.drawable.ic_download_pending;
+        } else if (failed) {
+            newIcon = android.R.drawable.stat_sys_download_done;
+        } else if (paused) {
+            newIcon = R.drawable.ic_download_pause;
+        } else if (completed) {
+            newIcon = R.drawable.offline_pin;
+        }
+
+        return new Pair<Boolean, Integer>(newIcon != oldIcon, newIcon);
+    }
+
+    /**
+     * Builds a summary notification that represents all downloads.
+     * {@see #buildSummaryNotification(Context)}.
+     * @param context A context used to query Android strings and resources.
+     * @param iconId  The id of an icon to use for the notification.
+     * @return        a {@link Notification} that represents the summary icon for all downloads.
+     */
+    private static Notification buildSummaryNotificationWithIcon(Context context, int iconId) {
+        ChromeNotificationBuilder builder =
+                NotificationBuilderFactory
+                        .createChromeNotificationBuilder(
+                                true /* preferCompat */, ChannelDefinitions.CHANNEL_ID_DOWNLOADS)
+                        .setContentTitle(
+                                context.getString(R.string.download_notification_summary_title))
+                        .setSubText(context.getString(R.string.menu_downloads))
+                        .setSmallIcon(iconId)
+                        .setLocalOnly(true)
+                        .setGroup(NotificationConstants.GROUP_DOWNLOADS)
+                        .setGroupSummary(true);
+        Bundle extras = new Bundle();
+        extras.putInt(EXTRA_NOTIFICATION_BUNDLE_ICON_ID, iconId);
+        builder.addExtras(extras);
+
+        // This notification should not actually be shown.  But if it is, set the click intent to
+        // open downloads home.
+        // TODO(dtrainor): Only do this if we have no transient downloads.
+        Intent downloadHomeIntent = buildActionIntent(
+                context, DownloadManager.ACTION_NOTIFICATION_CLICKED, null, false);
+        builder.setContentIntent(PendingIntent.getBroadcast(context,
+                NotificationConstants.NOTIFICATION_ID_DOWNLOAD_SUMMARY, downloadHomeIntent,
+                PendingIntent.FLAG_UPDATE_CURRENT));
+
+        return builder.build();
+    }
+
+    /**
+     * Builds a summary notification that represents downloads.  This is the notification passed to
+     * {@link #startForeground(int, Notification)}, which keeps this service in the foreground.
+     * @param context The context used to build the notification and pull specific resources.
+     * @return The {@link Notification} to show for the summary.  Meant to be used by
+     *         {@link NotificationManager#notify(int, Notification)}.
+     */
+    private static Notification buildSummaryNotification(
+            Context context, NotificationManager manager) {
+        Pair<Boolean, Integer> icon = getSummaryIcon(context, manager, -1, null);
+        return buildSummaryNotificationWithIcon(context, icon.second);
+    }
 
     /**
      * @return Whether or not there are any current resumable downloads being tracked.  These
      *         tracked downloads may not currently be showing notifications.
      */
-    static boolean isTrackingResumableDownloads(Context context) {
+    public static boolean isTrackingResumableDownloads(Context context) {
         List<DownloadSharedPreferenceEntry> entries =
                 DownloadSharedPreferenceHelper.getInstance().getEntries();
         for (DownloadSharedPreferenceEntry entry : entries) {
@@ -123,20 +412,334 @@
     }
 
     /**
-     * Track in-progress downloads here.
+     * Class for clients to access.
+     */
+    public class LocalBinder extends Binder {
+        DownloadNotificationService getService() {
+            return DownloadNotificationService.this;
+        }
+    }
+
+    @Override
+    public void onTaskRemoved(Intent rootIntent) {
+        super.onTaskRemoved(rootIntent);
+        // If we've lost all Activities, cancel the off the record downloads and validate that we
+        // should still be showing any download notifications at all.
+        if (ApplicationStatus.isEveryActivityDestroyed()) {
+            cancelOffTheRecordDownloads();
+            hideSummaryNotificationIfNecessary(-1);
+        }
+    }
+
+    @Override
+    public void onCreate() {
+        mContext = ContextUtils.getApplicationContext();
+        mNotificationManager =
+                (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+        mSharedPrefs = ContextUtils.getAppSharedPreferences();
+        mNumAutoResumptionAttemptLeft =
+                mSharedPrefs.getInt(KEY_AUTO_RESUMPTION_ATTEMPT_LEFT, MAX_RESUMPTION_ATTEMPT_LEFT);
+        mDownloadSharedPreferenceHelper = DownloadSharedPreferenceHelper.getInstance();
+        mNextNotificationId =
+                mSharedPrefs.getInt(KEY_NEXT_DOWNLOAD_NOTIFICATION_ID, STARTING_NOTIFICATION_ID);
+    }
+
+    @Override
+    public void onDestroy() {
+        updateNotificationsForShutdown();
+        rescheduleDownloads();
+        super.onDestroy();
+    }
+
+    @Override
+    public int onStartCommand(final Intent intent, int flags, int startId) {
+        // Start a foreground service every time we process a valid intent.  This makes sure we
+        // honor the promise that we'll be in the foreground when we start, even if we immediately
+        // drop ourselves back.
+        if (useForegroundService() && intent != null) startForegroundInternal();
+
+        if (intent == null) {
+            // Intent is only null during a process restart because of returning START_STICKY.  In
+            // this case cancel the off the record notifications and put the normal notifications
+            // into a pending state, then try to restart.  Finally validate that we are actually
+            // showing something.
+            updateNotificationsForShutdown();
+            handleDownloadOperation(
+                    new Intent(DownloadNotificationService.ACTION_DOWNLOAD_RESUME_ALL));
+            hideSummaryNotificationIfNecessary(-1);
+        } else if (TextUtils.equals(intent.getAction(),
+                           DownloadNotificationService.ACTION_DOWNLOAD_FAIL_SAFE)) {
+            hideSummaryNotificationIfNecessary(-1);
+        } else if (isDownloadOperationIntent(intent)) {
+            handleDownloadOperation(intent);
+            DownloadResumptionScheduler.getDownloadResumptionScheduler(mContext).cancelTask();
+            // Limit the number of auto resumption attempts in case Chrome falls into a vicious
+            // cycle.
+            if (ACTION_DOWNLOAD_RESUME_ALL.equals(intent.getAction())) {
+                if (mNumAutoResumptionAttemptLeft > 0) {
+                    mNumAutoResumptionAttemptLeft--;
+                    updateResumptionAttemptLeft();
+                }
+            } else {
+                // Reset number of attempts left if the action is triggered by user.
+                mNumAutoResumptionAttemptLeft = MAX_RESUMPTION_ATTEMPT_LEFT;
+                clearResumptionAttemptLeft();
+            }
+        }
+        // This should restart the service after Chrome gets killed. However, this
+        // doesn't work on Android 4.4.2.
+        return START_STICKY;
+    }
+
+    /**
+     * Adds an {@link Observer}, which will be notified when this service attempts to
+     * start stopping itself.
+     */
+    public void addObserver(Observer observer) {
+        mObservers.addObserver(observer);
+    }
+
+    /**
+     * Removes {@code observer}, which will no longer be notified when this class decides to start
+     * stopping itself.
+     */
+    public void removeObserver(Observer observer) {
+        mObservers.removeObserver(observer);
+    }
+
+    /**
+     * On >= O Android releases, puts this service into a background state.
+     * @param killNotification Whether or not this call should kill the summary notification or not.
+     *                         Not killing it puts the service into the background, but leaves the
+     *                         download notifications visible.
+     */
+    @VisibleForTesting
+    @TargetApi(Build.VERSION_CODES.N)
+    void stopForegroundInternal(boolean killNotification) {
+        if (!useForegroundService()) return;
+        stopForeground(killNotification ? STOP_FOREGROUND_REMOVE : STOP_FOREGROUND_DETACH);
+    }
+
+    /**
+     * On >= O Android releases, puts this service into a foreground state, binding it to the
+     * {@link Notification} generated by {@link #buildSummaryNotification(Context)}.
+     */
+    @VisibleForTesting
+    void startForegroundInternal() {
+        if (!useForegroundService()) return;
+        Notification notification =
+                buildSummaryNotification(getApplicationContext(), mNotificationManager);
+        startForeground(NotificationConstants.NOTIFICATION_ID_DOWNLOAD_SUMMARY, notification);
+    }
+
+    @VisibleForTesting
+    boolean hasDownloadNotificationsInternal(int notificationIdToIgnore) {
+        return hasDownloadNotifications(mNotificationManager, notificationIdToIgnore);
+    }
+
+    @VisibleForTesting
+    void updateSummaryIconInternal(
+            int removedNotificationId, Pair<Integer, Notification> addedNotification) {
+        updateSummaryIcon(mContext, mNotificationManager, removedNotificationId, addedNotification);
+    }
+
+    private void rescheduleDownloads() {
+        // Cancel any existing task.  If we have any downloads to resume we'll reschedule another
+        // one.
+        DownloadResumptionScheduler.getDownloadResumptionScheduler(mContext).cancelTask();
+        List<DownloadSharedPreferenceEntry> entries = mDownloadSharedPreferenceHelper.getEntries();
+        if (entries.isEmpty()) return;
+
+        boolean scheduleAutoResumption = false;
+        boolean allowMeteredConnection = false;
+        for (int i = 0; i < entries.size(); ++i) {
+            DownloadSharedPreferenceEntry entry = entries.get(i);
+            if (entry.isAutoResumable) {
+                scheduleAutoResumption = true;
+                if (entry.canDownloadWhileMetered) {
+                    allowMeteredConnection = true;
+                    break;
+                }
+            }
+        }
+
+        if (scheduleAutoResumption && mNumAutoResumptionAttemptLeft > 0) {
+            DownloadResumptionScheduler.getDownloadResumptionScheduler(mContext).schedule(
+                    allowMeteredConnection);
+        }
+    }
+
+    @VisibleForTesting
+    void updateNotificationsForShutdown() {
+        cancelOffTheRecordDownloads();
+        List<DownloadSharedPreferenceEntry> entries = mDownloadSharedPreferenceHelper.getEntries();
+        for (DownloadSharedPreferenceEntry entry : entries) {
+            if (entry.isOffTheRecord) continue;
+            // Move all regular downloads to pending.  Don't propagate the pause because
+            // if native is still working and it triggers an update, then the service will be
+            // restarted.
+            notifyDownloadPaused(entry.id, entry.fileName, !entry.isOffTheRecord, true,
+                    entry.isOffTheRecord, entry.isTransient, null);
+        }
+    }
+
+    @VisibleForTesting
+    void cancelOffTheRecordDownloads() {
+        boolean cancelActualDownload =
+                BrowserStartupController.get(LibraryProcessType.PROCESS_BROWSER)
+                        .isStartupSuccessfullyCompleted()
+                && Profile.getLastUsedProfile().hasOffTheRecordProfile();
+
+        List<DownloadSharedPreferenceEntry> entries = mDownloadSharedPreferenceHelper.getEntries();
+        List<DownloadSharedPreferenceEntry> copies =
+                new ArrayList<DownloadSharedPreferenceEntry>(entries);
+        for (DownloadSharedPreferenceEntry entry : copies) {
+            if (!entry.isOffTheRecord) continue;
+            ContentId id = entry.id;
+            notifyDownloadCanceled(id);
+            if (cancelActualDownload) {
+                DownloadServiceDelegate delegate = getServiceDelegate(id);
+                delegate.cancelDownload(id, true);
+                delegate.destroyServiceDelegate();
+            }
+            for (Observer observer : mObservers) observer.onDownloadCanceled(id);
+        }
+    }
+
+    /**
+     * Track in-progress downloads here and, if on an Android version >= O, make
+     * this a foreground service.
      * @param id The {@link ContentId} of the download that has been started and should be tracked.
      */
     private void startTrackingInProgressDownload(ContentId id) {
+        if (mDownloadsInProgress.size() == 0) startForegroundInternal();
         if (!mDownloadsInProgress.contains(id)) mDownloadsInProgress.add(id);
     }
 
     /**
-     * Stop tracking the download represented by {@code id}.
+     * Stop tracking the download represented by {@code id}.  If on an Android version >= O, stop
+     * making this a foreground service.
      * @param id                  The {@link ContentId} of the download that has been paused or
      *                            canceled and shouldn't be tracked.
+     * @param allowStopForeground Whether or not this should check internal state and stop the
+     *                            foreground notification from showing.  This could be false if we
+     *                            plan on removing the notification in the near future.  We don't
+     *                            want to just detach here, because that will put us in a
+     *                            potentially bad state where we cannot dismiss the notification.
      */
-    private void stopTrackingInProgressDownload(ContentId id) {
+    private void stopTrackingInProgressDownload(ContentId id, boolean allowStopForeground) {
         mDownloadsInProgress.remove(id);
+        if (allowStopForeground && mDownloadsInProgress.size() == 0) stopForegroundInternal(false);
+    }
+
+    /**
+     * @return The summary {@link StatusBarNotification} if one is showing.
+     */
+    @TargetApi(Build.VERSION_CODES.M)
+    private static StatusBarNotification getSummaryNotification(NotificationManager manager) {
+        if (!useForegroundService()) return null;
+
+        StatusBarNotification[] notifications = manager.getActiveNotifications();
+        for (StatusBarNotification notification : notifications) {
+            boolean isDownloadsGroup = TextUtils.equals(notification.getNotification().getGroup(),
+                    NotificationConstants.GROUP_DOWNLOADS);
+            boolean isSummaryNotification =
+                    notification.getId() == NotificationConstants.NOTIFICATION_ID_DOWNLOAD_SUMMARY;
+            if (isDownloadsGroup && isSummaryNotification) return notification;
+        }
+
+        return null;
+    }
+
+    /**
+     * Cancels the existing summary notification.  Moved to a helper method for test mocking.
+     */
+    @VisibleForTesting
+    void cancelSummaryNotification() {
+        mNotificationManager.cancel(NotificationConstants.NOTIFICATION_ID_DOWNLOAD_SUMMARY);
+    }
+
+    /**
+     * Check all current notifications and hide the summary notification if we have no downloads
+     * notifications left.  On Android if the user swipes away the last download notification the
+     * summary will be dismissed.  But if the last downloads notification is dismissed via
+     * {@link NotificationManager#cancel(int)}, the summary will remain, so we need to check and
+     * manually remove it ourselves.
+     * @param notificationIdToIgnore Canceling a notification and querying for the current list of
+     *                               active notifications isn't synchronous.  Pass a notification id
+     *                               here if there is a notification that should be assumed gone.
+     *                               Or pass -1 if no notification fits that criteria.
+     */
+    @SuppressWarnings("NewApi")
+    @SuppressLint("NewApi")
+    boolean hideSummaryNotificationIfNecessary(int notificationIdToIgnore) {
+        if (mDownloadsInProgress.size() > 0) return false;
+
+        if (useForegroundService()) {
+            if (hasDownloadNotificationsInternal(notificationIdToIgnore)) return false;
+
+            StatusBarNotification notification = getSummaryNotification(mNotificationManager);
+            if (notification != null) {
+                // We have a valid summary notification, but how we dismiss it depends on whether or
+                // not it is currently bound to this service via startForeground(...).
+                if ((notification.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE)
+                        != 0) {
+                    // If we are a foreground service and we are hiding the notification, we have no
+                    // other downloads notifications showing, so we need to remove the notification
+                    // and unregister it from this service at the same time.
+                    stopForegroundInternal(true);
+                } else {
+                    // If we are not a foreground service, remove the notification via the
+                    // NotificationManager.  The notification is not bound to this service, so any
+                    // call to stopForeground() won't affect the notification.
+                    cancelSummaryNotification();
+                }
+            } else {
+                // If we don't have a valid summary, just guarantee that we aren't in the foreground
+                // for safety.  Still try to remove the summary notification to make sure it's gone.
+                // This is because querying for it might fail if we have just recently started up
+                // and began showing it.  This might leave us in a bad state if the cancel request
+                // fails inside the framework.
+                // TODO(dtrainor): Add a way to attempt to automatically clean up the notification
+                // shortly after this.
+                stopForegroundInternal(true);
+            }
+        } else {
+            // If we're not using a foreground service, just shut down after we are no longer
+            // tracking any downloads.
+            if (mDownloadSharedPreferenceHelper.getEntries().size() > 0) return false;
+        }
+
+        // Stop the service which should start the destruction process.  At this point we should be
+        // a background service.  We might not be unbound from any clients.  When they unbind we
+        // will shut down.  That is okay because they will only unbind from us when they are ok with
+        // us going away (e.g. we shouldn't be unbound while in the foreground).
+        stopSelf();
+        return true;
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mBinder;
+    }
+
+    /**
+     * Helper method to update the remaining number of background resumption attempts left.
+     */
+    private void updateResumptionAttemptLeft() {
+        SharedPreferences.Editor editor = mSharedPrefs.edit();
+        editor.putInt(KEY_AUTO_RESUMPTION_ATTEMPT_LEFT, mNumAutoResumptionAttemptLeft);
+        editor.apply();
+    }
+
+    /**
+     * Helper method to clear the remaining number of background resumption attempts left.
+     */
+    static void clearResumptionAttemptLeft() {
+        SharedPreferences SharedPrefs = ContextUtils.getAppSharedPreferences();
+        SharedPreferences.Editor editor = SharedPrefs.edit();
+        editor.remove(KEY_AUTO_RESUMPTION_ATTEMPT_LEFT);
+        editor.apply();
     }
 
     /**
@@ -157,8 +760,9 @@
     public void notifyDownloadProgress(ContentId id, String fileName, Progress progress,
             long bytesReceived, long timeRemainingInMillis, long startTime, boolean isOffTheRecord,
             boolean canDownloadWhileMetered, boolean isTransient, Bitmap icon) {
-        updateActiveDownloadNotification(id, fileName, progress, timeRemainingInMillis, startTime,
-                isOffTheRecord, canDownloadWhileMetered, false, isTransient, icon, false);
+        updateActiveDownloadNotification(id, fileName, progress, bytesReceived,
+                timeRemainingInMillis, startTime, isOffTheRecord, canDownloadWhileMetered, false,
+                isTransient, icon);
     }
 
     /**
@@ -171,11 +775,10 @@
      *                                downloads home.
      * @param icon                    A {@link Bitmap} to be used as the large icon for display.
      */
-    void notifyDownloadPending(ContentId id, String fileName, boolean isOffTheRecord,
-            boolean canDownloadWhileMetered, boolean isTransient, Bitmap icon,
-            boolean hasUserGesture) {
+    private void notifyDownloadPending(ContentId id, String fileName, boolean isOffTheRecord,
+            boolean canDownloadWhileMetered, boolean isTransient, Bitmap icon) {
         updateActiveDownloadNotification(id, fileName, Progress.createIndeterminateProgress(), 0, 0,
-                isOffTheRecord, canDownloadWhileMetered, true, isTransient, icon, hasUserGesture);
+                0, isOffTheRecord, canDownloadWhileMetered, true, isTransient, icon);
     }
 
     /**
@@ -184,6 +787,7 @@
      * @param id                      The {@link ContentId} of the download.
      * @param fileName                File name of the download.
      * @param progress                The current download progress.
+     * @param bytesReceived           Total number of bytes received.
      * @param timeRemainingInMillis   Remaining download time in milliseconds or -1 if it is
      *                                unknown.
      * @param startTime               Time when download started.
@@ -195,48 +799,70 @@
      * @param icon                    A {@link Bitmap} to be used as the large icon for display.
      */
     private void updateActiveDownloadNotification(ContentId id, String fileName, Progress progress,
-            long timeRemainingInMillis, long startTime, boolean isOffTheRecord,
+            long bytesReceived, long timeRemainingInMillis, long startTime, boolean isOffTheRecord,
             boolean canDownloadWhileMetered, boolean isDownloadPending, boolean isTransient,
-            Bitmap icon, boolean hasUserGesture) {
-        Context context = ContextUtils.getApplicationContext();
-        int notificationId = getNotificationId(id);
-        DownloadUpdate downloadUpdate = new DownloadUpdate.Builder()
-                                                .setContentId(id)
-                                                .setFileName(fileName)
-                                                .setProgress(progress)
-                                                .setTimeRemainingInMillis(timeRemainingInMillis)
-                                                .setStartTime(startTime)
-                                                .setIsOffTheRecord(isOffTheRecord)
-                                                .setIsDownloadPending(isDownloadPending)
-                                                .setIsTransient(isTransient)
-                                                .setIcon(icon)
-                                                .setNotificationId(notificationId)
-                                                .build();
-        Notification notification = DownloadNotificationFactory.buildNotification(
-                context, DownloadNotificationFactory.DownloadStatus.IN_PROGRESS, downloadUpdate);
+            Bitmap icon) {
+        boolean indeterminate = (progress.isIndeterminate() || isDownloadPending);
+        String contentText = null;
+        if (isDownloadPending) {
+            contentText = mContext.getResources().getString(R.string.download_notification_pending);
+        } else if (indeterminate || timeRemainingInMillis < 0) {
+            // TODO(dimich): Enable the byte count back in M59. See bug 704049 for more info and
+            // details of what was temporarily reverted (for M58).
+            contentText = mContext.getResources().getString(R.string.download_started);
+        } else {
+            contentText = DownloadUtils.getTimeOrFilesLeftString(
+                    mContext, progress, timeRemainingInMillis);
+        }
+        int resId = isDownloadPending ? R.drawable.ic_download_pending
+                                      : android.R.drawable.stat_sys_download;
+        ChromeNotificationBuilder builder = buildNotification(resId, fileName, contentText);
+        builder.setOngoing(true);
+        builder.setPriority(Notification.PRIORITY_HIGH);
 
-        // If called from DownloadBroadcastManager, only update notification, not tracking.
-        if (hasUserGesture) {
-            updateNotification(notificationId, notification);
-            return;
+        // Avoid animations while the download isn't progressing.
+        if (!isDownloadPending) {
+            builder.setProgress(100, indeterminate ? -1 : progress.getPercentage(), indeterminate);
         }
 
-        updateNotification(notificationId, notification, id,
+        if (!indeterminate && !LegacyHelpers.isLegacyOfflinePage(id)) {
+            String percentText = DownloadUtils.getPercentageString(progress.getPercentage());
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+                builder.setSubText(percentText);
+            } else {
+                builder.setContentInfo(percentText);
+            }
+        }
+        int notificationId = getNotificationId(id);
+        if (startTime > 0) builder.setWhen(startTime);
+
+        if (!isTransient) {
+            // Clicking on an in-progress download sends the user to see all their downloads.
+            Intent downloadHomeIntent = buildActionIntent(
+                    mContext, DownloadManager.ACTION_NOTIFICATION_CLICKED, null, isOffTheRecord);
+            builder.setContentIntent(PendingIntent.getBroadcast(mContext, notificationId,
+                    downloadHomeIntent, PendingIntent.FLAG_UPDATE_CURRENT));
+        }
+        builder.setAutoCancel(false);
+        if (icon != null) builder.setLargeIcon(icon);
+
+        Intent pauseIntent = buildActionIntent(mContext, ACTION_DOWNLOAD_PAUSE, id, isOffTheRecord);
+        builder.addAction(R.drawable.ic_pause_white_24dp,
+                mContext.getResources().getString(R.string.download_notification_pause_button),
+                buildPendingIntent(pauseIntent, notificationId));
+
+        Intent cancelIntent =
+                buildActionIntent(mContext, ACTION_DOWNLOAD_CANCEL, id, isOffTheRecord);
+        builder.addAction(R.drawable.btn_close_white,
+                mContext.getResources().getString(R.string.download_notification_cancel_button),
+                buildPendingIntent(cancelIntent, notificationId));
+
+        updateNotification(notificationId, builder.build(), id,
                 new DownloadSharedPreferenceEntry(id, notificationId, isOffTheRecord,
                         canDownloadWhileMetered, fileName, true, isTransient));
-        // TODO(jming): do we want to handle the pending option in a different manner?
-        mDownloadForegroundServiceManager.updateDownloadStatus(context,
-                DownloadForegroundServiceManager.DownloadStatus.IN_PROGRESS, notificationId,
-                notification);
-
         startTrackingInProgressDownload(id);
     }
 
-    public void cancelNotification(int notificationId) {
-        // TODO(b/65052774): Add back NOTIFICATION_NAMESPACE when able to.
-        mNotificationManager.cancel(notificationId);
-    }
-
     /**
      * Removes a download notification and all associated tracking.  This method relies on the
      * caller to provide the notification id, which is useful in the case where the internal
@@ -246,10 +872,16 @@
      * @param id The {@link ContentId} of the download.
      */
     public void cancelNotification(int notificationId, ContentId id) {
-        cancelNotification(notificationId);
+        mNotificationManager.cancel(NOTIFICATION_NAMESPACE, notificationId);
         mDownloadSharedPreferenceHelper.removeSharedPreferenceEntry(id);
 
-        stopTrackingInProgressDownload(id);
+        // Since we are about to go through the process of validating whether or not we can shut
+        // down, don't stop foreground if we have no download notifications left to show.  Hiding
+        // the summary will take care of that for us.
+        stopTrackingInProgressDownload(id, hasDownloadNotificationsInternal(notificationId));
+        if (!hideSummaryNotificationIfNecessary(notificationId)) {
+            updateSummaryIcon(mContext, mNotificationManager, notificationId, null);
+        }
     }
 
     /**
@@ -258,20 +890,11 @@
      * @param id The {@link ContentId} of the download.
      */
     @VisibleForTesting
-    public void notifyDownloadCanceled(ContentId id, boolean hasUserGesture) {
+    public void notifyDownloadCanceled(ContentId id) {
         DownloadSharedPreferenceEntry entry =
                 mDownloadSharedPreferenceHelper.getDownloadSharedPreferenceEntry(id);
         if (entry == null) return;
-
-        // If called from DownloadBroadcastManager, only update notification, not tracking.
-        if (hasUserGesture) {
-            cancelNotification(entry.notificationId);
-            return;
-        }
-
         cancelNotification(entry.notificationId, id);
-        mDownloadForegroundServiceManager.updateDownloadStatus(ContextUtils.getApplicationContext(),
-                DownloadForegroundServiceManager.DownloadStatus.CANCEL, entry.notificationId, null);
     }
 
     /**
@@ -284,10 +907,8 @@
      * @param isTransient     Whether or not clicking on the download should launch downloads home.
      * @param icon            A {@link Bitmap} to be used as the large icon for display.
      */
-    @VisibleForTesting
-    void notifyDownloadPaused(ContentId id, String fileName, boolean isResumable,
-            boolean isAutoResumable, boolean isOffTheRecord, boolean isTransient, Bitmap icon,
-            boolean hasUserGesture) {
+    public void notifyDownloadPaused(ContentId id, String fileName, boolean isResumable,
+            boolean isAutoResumable, boolean isOffTheRecord, boolean isTransient, Bitmap icon) {
         DownloadSharedPreferenceEntry entry =
                 mDownloadSharedPreferenceHelper.getDownloadSharedPreferenceEntry(id);
         if (!isResumable) {
@@ -299,39 +920,46 @@
         boolean canDownloadWhileMetered = entry == null ? false : entry.canDownloadWhileMetered;
         // If download is interrupted due to network disconnection, show download pending state.
         if (isAutoResumable) {
-            notifyDownloadPending(id, fileName, isOffTheRecord, canDownloadWhileMetered,
-                    isTransient, icon, hasUserGesture);
-            stopTrackingInProgressDownload(id);
+            notifyDownloadPending(
+                    id, fileName, isOffTheRecord, canDownloadWhileMetered, isTransient, icon);
+            stopTrackingInProgressDownload(id, true);
             return;
         }
 
-        Context context = ContextUtils.getApplicationContext();
+        String contentText =
+                mContext.getResources().getString(R.string.download_notification_paused);
+        ChromeNotificationBuilder builder =
+                buildNotification(R.drawable.ic_download_pause, fileName, contentText);
         int notificationId = entry == null ? getNotificationId(id) : entry.notificationId;
-        DownloadUpdate downloadUpdate = new DownloadUpdate.Builder()
-                                                .setContentId(id)
-                                                .setFileName(fileName)
-                                                .setIsOffTheRecord(isOffTheRecord)
-                                                .setIsTransient(isTransient)
-                                                .setIcon(icon)
-                                                .setNotificationId(notificationId)
-                                                .build();
-        Notification notification = DownloadNotificationFactory.buildNotification(
-                context, DownloadNotificationFactory.DownloadStatus.PAUSED, downloadUpdate);
-        updateNotification(notificationId, notification, id,
+        if (!isTransient) {
+            // Clicking on an in-progress download sends the user to see all their downloads.
+            Intent downloadHomeIntent = buildActionIntent(
+                    mContext, DownloadManager.ACTION_NOTIFICATION_CLICKED, null, false);
+            builder.setContentIntent(PendingIntent.getBroadcast(mContext, notificationId,
+                    downloadHomeIntent, PendingIntent.FLAG_UPDATE_CURRENT));
+        }
+        builder.setAutoCancel(false);
+        if (icon != null) builder.setLargeIcon(icon);
+
+        Intent resumeIntent =
+                buildActionIntent(mContext, ACTION_DOWNLOAD_RESUME, id, isOffTheRecord);
+        builder.addAction(R.drawable.ic_file_download_white_24dp,
+                mContext.getResources().getString(R.string.download_notification_resume_button),
+                buildPendingIntent(resumeIntent, notificationId));
+
+        Intent cancelIntent =
+                buildActionIntent(mContext, ACTION_DOWNLOAD_CANCEL, id, isOffTheRecord);
+        builder.addAction(R.drawable.btn_close_white,
+                mContext.getResources().getString(R.string.download_notification_cancel_button),
+                buildPendingIntent(cancelIntent, notificationId));
+        PendingIntent deleteIntent = isTransient ? buildPendingIntent(cancelIntent, notificationId)
+                                                 : buildSummaryIconIntent(notificationId);
+        builder.setDeleteIntent(deleteIntent);
+
+        updateNotification(notificationId, builder.build(), id,
                 new DownloadSharedPreferenceEntry(id, notificationId, isOffTheRecord,
                         canDownloadWhileMetered, fileName, isAutoResumable, isTransient));
-
-        // If called from DownloadBroadcastManager, only update notification, not tracking.
-        if (hasUserGesture) {
-            updateNotification(notificationId, notification);
-            return;
-        }
-
-        mDownloadForegroundServiceManager.updateDownloadStatus(context,
-                DownloadForegroundServiceManager.DownloadStatus.PAUSE, notificationId,
-                notification);
-
-        stopTrackingInProgressDownload(id);
+        stopTrackingInProgressDownload(id, true);
     }
 
     /**
@@ -352,36 +980,42 @@
     public int notifyDownloadSuccessful(ContentId id, String filePath, String fileName,
             long systemDownloadId, boolean isOffTheRecord, boolean isSupportedMimeType,
             boolean isOpenable, Bitmap icon, String originalUrl, String referrer) {
-        Context context = ContextUtils.getApplicationContext();
         int notificationId = getNotificationId(id);
+        ChromeNotificationBuilder builder = buildNotification(R.drawable.offline_pin, fileName,
+                mContext.getResources().getString(R.string.download_notification_completed));
+        ComponentName component = new ComponentName(
+                mContext.getPackageName(), DownloadBroadcastReceiver.class.getName());
+
+        if (isOpenable) {
+            Intent intent = null;
+            if (LegacyHelpers.isLegacyDownload(id)) {
+                intent = new Intent(DownloadManager.ACTION_NOTIFICATION_CLICKED);
+                long[] idArray = {systemDownloadId};
+                intent.putExtra(DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS, idArray);
+                intent.putExtra(EXTRA_DOWNLOAD_FILE_PATH, filePath);
+                intent.putExtra(EXTRA_IS_SUPPORTED_MIME_TYPE, isSupportedMimeType);
+                intent.putExtra(EXTRA_IS_OFF_THE_RECORD, isOffTheRecord);
+                intent.putExtra(EXTRA_DOWNLOAD_CONTENTID_ID, id.id);
+                intent.putExtra(EXTRA_DOWNLOAD_CONTENTID_NAMESPACE, id.namespace);
+                intent.putExtra(NotificationConstants.EXTRA_NOTIFICATION_ID, notificationId);
+                DownloadUtils.setOriginalUrlAndReferralExtraToIntent(intent, originalUrl, referrer);
+            } else {
+                intent = buildActionIntent(mContext, ACTION_DOWNLOAD_OPEN, id, false);
+            }
+
+            intent.setComponent(component);
+            builder.setContentIntent(PendingIntent.getBroadcast(
+                    mContext, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT));
+        }
         if (icon == null && mDownloadSuccessLargeIcon == null) {
             Bitmap bitmap =
-                    BitmapFactory.decodeResource(context.getResources(), R.drawable.offline_pin);
+                    BitmapFactory.decodeResource(mContext.getResources(), R.drawable.offline_pin);
             mDownloadSuccessLargeIcon = getLargeNotificationIcon(bitmap);
         }
-        if (icon == null) icon = mDownloadSuccessLargeIcon;
-
-        DownloadUpdate downloadUpdate = new DownloadUpdate.Builder()
-                                                .setContentId(id)
-                                                .setFileName(fileName)
-                                                .setFilePath(filePath)
-                                                .setSystemDownload(systemDownloadId)
-                                                .setIsOffTheRecord(isOffTheRecord)
-                                                .setIsSupportedMimeType(isSupportedMimeType)
-                                                .setIsOpenable(isOpenable)
-                                                .setIcon(icon)
-                                                .setNotificationId(notificationId)
-                                                .setOriginalUrl(originalUrl)
-                                                .setReferrer(referrer)
-                                                .build();
-        Notification notification = DownloadNotificationFactory.buildNotification(
-                context, DownloadNotificationFactory.DownloadStatus.SUCCESSFUL, downloadUpdate);
-
-        updateNotification(notificationId, notification, id, null);
-        mDownloadForegroundServiceManager.updateDownloadStatus(context,
-                DownloadForegroundServiceManager.DownloadStatus.COMPLETE, notificationId,
-                notification);
-        stopTrackingInProgressDownload(id);
+        builder.setDeleteIntent(buildSummaryIconIntent(notificationId));
+        builder.setLargeIcon(icon != null ? icon : mDownloadSuccessLargeIcon);
+        updateNotification(notificationId, builder.build(), id, null);
+        stopTrackingInProgressDownload(id, true);
         return notificationId;
     }
 
@@ -402,25 +1036,80 @@
             fileName = entry.fileName;
         }
 
-        Context context = ContextUtils.getApplicationContext();
         int notificationId = getNotificationId(id);
-        DownloadUpdate downloadUpdate = new DownloadUpdate.Builder()
-                                                .setContentId(id)
-                                                .setFileName(fileName)
-                                                .setIcon(icon)
-                                                .build();
-        Notification notification = DownloadNotificationFactory.buildNotification(
-                context, DownloadNotificationFactory.DownloadStatus.FAILED, downloadUpdate);
+        ChromeNotificationBuilder builder =
+                buildNotification(android.R.drawable.stat_sys_download_done, fileName,
+                        mContext.getResources().getString(R.string.download_notification_failed));
+        if (icon != null) builder.setLargeIcon(icon);
+        builder.setDeleteIntent(buildSummaryIconIntent(notificationId));
+        updateNotification(notificationId, builder.build(), id, null);
+        stopTrackingInProgressDownload(id, true);
+    }
 
-        updateNotification(notificationId, notification, id, null);
-        mDownloadForegroundServiceManager.updateDownloadStatus(context,
-                DownloadForegroundServiceManager.DownloadStatus.FAIL, notificationId, notification);
+    /**
+     * Helper method to build a PendingIntent from the provided intent.
+     * @param intent Intent to broadcast.
+     * @param notificationId ID of the notification.
+     */
+    private PendingIntent buildPendingIntent(Intent intent, int notificationId) {
+        return PendingIntent.getBroadcast(
+                mContext, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+    }
 
-        stopTrackingInProgressDownload(id);
+    private PendingIntent buildSummaryIconIntent(int notificationId) {
+        Intent intent = new Intent(mContext, DownloadBroadcastReceiver.class);
+        intent.setAction(ACTION_DOWNLOAD_UPDATE_SUMMARY_ICON);
+        return buildPendingIntent(intent, notificationId);
+    }
+
+    /**
+     * Helper method to build an download action Intent from the provided information.
+     * @param context {@link Context} to pull resources from.
+     * @param action Download action to perform.
+     * @param id The {@link ContentId} of the download.
+     * @param isOffTheRecord Whether the download is incognito.
+     */
+    static Intent buildActionIntent(
+            Context context, String action, ContentId id, boolean isOffTheRecord) {
+        ComponentName component = new ComponentName(
+                context.getPackageName(), DownloadBroadcastReceiver.class.getName());
+        Intent intent = new Intent(action);
+        intent.setComponent(component);
+        intent.putExtra(EXTRA_DOWNLOAD_CONTENTID_ID, id != null ? id.id : "");
+        intent.putExtra(EXTRA_DOWNLOAD_CONTENTID_NAMESPACE, id != null ? id.namespace : "");
+        intent.putExtra(EXTRA_IS_OFF_THE_RECORD, isOffTheRecord);
+        return intent;
+    }
+
+    /**
+     * Builds a notification to be displayed.
+     * @param iconId Id of the notification icon.
+     * @param title Title of the notification.
+     * @param contentText Notification content text to be displayed.
+     * @return notification builder that builds the notification to be displayed
+     */
+    private ChromeNotificationBuilder buildNotification(
+            int iconId, String title, String contentText) {
+        Bundle extras = new Bundle();
+        extras.putInt(EXTRA_NOTIFICATION_BUNDLE_ICON_ID, iconId);
+
+        ChromeNotificationBuilder builder =
+                NotificationBuilderFactory
+                        .createChromeNotificationBuilder(
+                                true /* preferCompat */, ChannelDefinitions.CHANNEL_ID_DOWNLOADS)
+                        .setContentTitle(
+                                DownloadUtils.getAbbreviatedFileName(title, MAX_FILE_NAME_LENGTH))
+                        .setSmallIcon(iconId)
+                        .setLocalOnly(true)
+                        .setAutoCancel(true)
+                        .setContentText(contentText)
+                        .setGroup(NotificationConstants.GROUP_DOWNLOADS)
+                        .addExtras(extras);
+        return builder;
     }
 
     private Bitmap getLargeNotificationIcon(Bitmap bitmap) {
-        Resources resources = ContextUtils.getApplicationContext().getResources();
+        Resources resources = mContext.getResources();
         int height = (int) resources.getDimension(android.R.dimen.notification_large_icon_height);
         int width = (int) resources.getDimension(android.R.dimen.notification_large_icon_width);
         final OvalShape circle = new OvalShape();
@@ -445,10 +1134,189 @@
         return result;
     }
 
+    /**
+     * Retrieves DownloadSharedPreferenceEntry from a download action intent.
+     * @param intent Intent that contains the download action.
+     */
+    private DownloadSharedPreferenceEntry getDownloadEntryFromIntent(Intent intent) {
+        if (ACTION_DOWNLOAD_RESUME_ALL.equals(intent.getAction())) return null;
+        return mDownloadSharedPreferenceHelper.getDownloadSharedPreferenceEntry(
+                getContentIdFromIntent(intent));
+    }
+
+    /**
+     * Helper method to launch the browser process and handle a download operation that is included
+     * in the given intent.
+     * @param intent Intent with the download operation.
+     */
+    private void handleDownloadOperation(final Intent intent) {
+        // Process updating the summary notification first.  This has no impact on a specific
+        // download.
+        if (ACTION_DOWNLOAD_UPDATE_SUMMARY_ICON.equals(intent.getAction())) {
+            updateSummaryIcon(mContext, mNotificationManager, -1, null);
+            hideSummaryNotificationIfNecessary(-1);
+            return;
+        }
+
+        // TODO(qinmin): Figure out how to properly handle this case.
+        final ContentId id = getContentIdFromIntent(intent);
+        final DownloadSharedPreferenceEntry entry = getDownloadEntryFromIntent(intent);
+        if (entry == null
+                && !(id != null && LegacyHelpers.isLegacyOfflinePage(id)
+                           && TextUtils.equals(intent.getAction(), ACTION_DOWNLOAD_OPEN))) {
+            handleDownloadOperationForMissingNotification(intent);
+            hideSummaryNotificationIfNecessary(-1);
+            return;
+        }
+
+        if (ACTION_DOWNLOAD_PAUSE.equals(intent.getAction())) {
+            // If browser process already goes away, the download should have already paused. Do
+            // nothing in that case.
+            if (!DownloadManagerService.hasDownloadManagerService()) {
+                // TODO(dtrainor): Should we spin up native to make sure we have the icon?  Or maybe
+                // build a Java cache for easy access.
+                notifyDownloadPaused(entry.id, entry.fileName, !entry.isOffTheRecord, false,
+                        entry.isOffTheRecord, entry.isTransient, null);
+                hideSummaryNotificationIfNecessary(-1);
+                return;
+            }
+        } else if (ACTION_DOWNLOAD_RESUME.equals(intent.getAction())) {
+            // If user manually resumes a download, update the network type if it
+            // is not metered previously.
+            boolean canDownloadWhileMetered = entry.canDownloadWhileMetered
+                    || DownloadManagerService.isActiveNetworkMetered(mContext);
+            // Update the SharedPreference entry.
+            mDownloadSharedPreferenceHelper.addOrReplaceSharedPreferenceEntry(
+                    new DownloadSharedPreferenceEntry(entry.id, entry.notificationId,
+                            entry.isOffTheRecord, canDownloadWhileMetered, entry.fileName, true,
+                            entry.isTransient));
+        } else if (ACTION_DOWNLOAD_RESUME_ALL.equals(intent.getAction())
+                && (mDownloadSharedPreferenceHelper.getEntries().isEmpty()
+                           || DownloadManagerService.hasDownloadManagerService())) {
+            hideSummaryNotificationIfNecessary(-1);
+            return;
+        } else if (ACTION_DOWNLOAD_OPEN.equals(intent.getAction())) {
+            // TODO(fgorski): Do we even need to do anything special here, before we launch Chrome?
+        } else if (ACTION_DOWNLOAD_CANCEL.equals(intent.getAction())
+                && IntentUtils.safeGetBooleanExtra(intent, EXTRA_NOTIFICATION_DISMISSED, false)) {
+            // User canceled a download by dismissing its notification from earlier versions, ignore
+            // it. TODO(qinmin): remove this else-if block after M60.
+            return;
+        }
+
+        BrowserParts parts = new EmptyBrowserParts() {
+            @Override
+            public void finishNativeInitialization() {
+                // Make sure the OfflineContentAggregator bridge is initialized.
+                OfflineContentAggregatorNotificationBridgeUiFactory.instance();
+
+                DownloadServiceDelegate downloadServiceDelegate =
+                        ACTION_DOWNLOAD_OPEN.equals(intent.getAction()) ? null
+                                                                        : getServiceDelegate(id);
+                if (ACTION_DOWNLOAD_CANCEL.equals(intent.getAction())) {
+                    // TODO(qinmin): Alternatively, we can delete the downloaded content on
+                    // SD card, and remove the download ID from the SharedPreferences so we
+                    // don't need to restart the browser process. http://crbug.com/579643.
+                    cancelNotification(entry.notificationId, entry.id);
+                    downloadServiceDelegate.cancelDownload(entry.id, entry.isOffTheRecord);
+                    for (Observer observer : mObservers) {
+                        observer.onDownloadCanceled(entry.id);
+                    }
+                } else if (ACTION_DOWNLOAD_PAUSE.equals(intent.getAction())) {
+                    // TODO(dtrainor): Consider hitting the delegate and rely on that to update the
+                    // state.
+                    notifyDownloadPaused(entry.id, entry.fileName, true, false,
+                            entry.isOffTheRecord, entry.isTransient, null);
+                    downloadServiceDelegate.pauseDownload(entry.id, entry.isOffTheRecord);
+                } else if (ACTION_DOWNLOAD_RESUME.equals(intent.getAction())) {
+                    // TODO(dtrainor): Consider hitting the delegate and rely on that to update the
+                    // state.
+                    notifyDownloadPending(entry.id, entry.fileName, entry.isOffTheRecord,
+                            entry.canDownloadWhileMetered, entry.isTransient, null);
+                    downloadServiceDelegate.resumeDownload(
+                            entry.id, entry.buildDownloadItem(), true);
+                } else if (ACTION_DOWNLOAD_RESUME_ALL.equals(intent.getAction())) {
+                    assert entry == null;
+                    resumeAllPendingDownloads();
+                } else if (ACTION_DOWNLOAD_OPEN.equals(intent.getAction())) {
+                    ContentId id = getContentIdFromIntent(intent);
+                    if (LegacyHelpers.isLegacyOfflinePage(id)) {
+                        OfflinePageDownloadBridge.openDownloadedPage(id);
+                    } else if (id != null) {
+                        OfflineContentAggregatorNotificationBridgeUiFactory.instance().openItem(id);
+                    }
+                } else {
+                    Log.e(TAG, "Unrecognized intent action.", intent);
+                }
+                if (!ACTION_DOWNLOAD_OPEN.equals(intent.getAction())) {
+                    downloadServiceDelegate.destroyServiceDelegate();
+                }
+
+                hideSummaryNotificationIfNecessary(ACTION_DOWNLOAD_CANCEL.equals(intent.getAction())
+                                ? entry.notificationId
+                                : -1);
+            }
+        };
+        try {
+            ChromeBrowserInitializer.getInstance(mContext).handlePreNativeStartup(parts);
+            ChromeBrowserInitializer.getInstance(mContext).handlePostNativeStartup(true, parts);
+        } catch (ProcessInitException e) {
+            Log.e(TAG, "Unable to load native library.", e);
+            ChromeApplication.reportStartupErrorAndExit(e);
+        }
+    }
+
+    /**
+     * Handles operations for downloads that the DownloadNotificationService is unaware of.
+     *
+     * This can happen because the DownloadNotificationService learn about downloads later than
+     * Download Home does, and may not yet have a DownloadSharedPreferenceEntry for the item.
+     *
+     * TODO(qinmin): Figure out how to fix the SharedPreferences so that it properly tracks entries.
+     */
+    private void handleDownloadOperationForMissingNotification(Intent intent) {
+        // This function should only be called via Download Home, but catch this case to be safe.
+        if (!DownloadManagerService.hasDownloadManagerService()) return;
+
+        String action = intent.getAction();
+        ContentId id = getContentIdFromIntent(intent);
+        boolean isOffTheRecord =
+                IntentUtils.safeGetBooleanExtra(intent, EXTRA_IS_OFF_THE_RECORD, false);
+        if (!LegacyHelpers.isLegacyDownload(id)) return;
+
+        // Pass information directly to the DownloadManagerService.
+        if (TextUtils.equals(action, ACTION_DOWNLOAD_CANCEL)) {
+            getServiceDelegate(id).cancelDownload(id, isOffTheRecord);
+        } else if (TextUtils.equals(action, ACTION_DOWNLOAD_PAUSE)) {
+            getServiceDelegate(id).pauseDownload(id, isOffTheRecord);
+        } else if (TextUtils.equals(action, ACTION_DOWNLOAD_RESUME)) {
+            DownloadInfo info = new DownloadInfo.Builder()
+                                        .setDownloadGuid(id.id)
+                                        .setIsOffTheRecord(isOffTheRecord)
+                                        .build();
+            getServiceDelegate(id).resumeDownload(id, new DownloadItem(false, info), true);
+        }
+    }
+
+    /**
+     * Gets appropriate download delegate that can handle interactions with download item referred
+     * to by the entry.
+     * @param id The {@link ContentId} to grab the delegate for.
+     * @return delegate for interactions with the entry
+     */
+    DownloadServiceDelegate getServiceDelegate(ContentId id) {
+        if (LegacyHelpers.isLegacyOfflinePage(id)) {
+            return OfflinePageDownloadBridge.getDownloadServiceDelegate();
+        }
+        if (LegacyHelpers.isLegacyDownload(id)) {
+            return DownloadManagerService.getDownloadManagerService();
+        }
+        return OfflineContentAggregatorNotificationBridgeUiFactory.instance();
+    }
+
     @VisibleForTesting
     void updateNotification(int id, Notification notification) {
-        // TODO(b/65052774): Add back NOTIFICATION_NAMESPACE when able to.
-        mNotificationManager.notify(id, notification);
+        mNotificationManager.notify(NOTIFICATION_NAMESPACE, id, notification);
     }
 
     private void updateNotification(int notificationId, Notification notification, ContentId id,
@@ -461,6 +1329,8 @@
         } else {
             mDownloadSharedPreferenceHelper.removeSharedPreferenceEntry(id);
         }
+        updateSummaryIcon(mContext, mNotificationManager, -1,
+                new Pair<Integer, Notification>(notificationId, notification));
     }
 
     private void trackNotificationUma(ContentId id) {
@@ -474,6 +1344,27 @@
                 ChannelDefinitions.CHANNEL_ID_DOWNLOADS);
     }
 
+    /**
+     * Checks if an intent requires operations on a download.
+     * @param intent An intent to validate.
+     * @return true if the intent requires actions, or false otherwise.
+     */
+    static boolean isDownloadOperationIntent(Intent intent) {
+        if (intent == null) return false;
+        if (ACTION_DOWNLOAD_UPDATE_SUMMARY_ICON.equals(intent.getAction())) return true;
+        if (ACTION_DOWNLOAD_RESUME_ALL.equals(intent.getAction())) return true;
+        if (!ACTION_DOWNLOAD_CANCEL.equals(intent.getAction())
+                && !ACTION_DOWNLOAD_RESUME.equals(intent.getAction())
+                && !ACTION_DOWNLOAD_PAUSE.equals(intent.getAction())
+                && !ACTION_DOWNLOAD_OPEN.equals(intent.getAction())) {
+            return false;
+        }
+
+        ContentId id = getContentIdFromIntent(intent);
+        if (id == null) return false;
+        return true;
+    }
+
     private static boolean canResumeDownload(Context context, DownloadSharedPreferenceEntry entry) {
         if (entry == null) return false;
         if (!entry.isAutoResumable) return false;
@@ -483,31 +1374,41 @@
     }
 
     /**
+     * @param intent The {@link Intent} to pull from and build a {@link ContentId}.
+     * @return A {@link ContentId} built by pulling extras from {@code intent}.  This will be
+     *         {@code null} if {@code intent} is missing any required extras.
+     */
+    public static ContentId getContentIdFromIntent(Intent intent) {
+        if (!intent.hasExtra(EXTRA_DOWNLOAD_CONTENTID_ID)
+                || !intent.hasExtra(EXTRA_DOWNLOAD_CONTENTID_NAMESPACE)) {
+            return null;
+        }
+
+        return new ContentId(
+                IntentUtils.safeGetStringExtra(intent, EXTRA_DOWNLOAD_CONTENTID_NAMESPACE),
+                IntentUtils.safeGetStringExtra(intent, EXTRA_DOWNLOAD_CONTENTID_ID));
+    }
+
+    /**
      * Resumes all pending downloads from SharedPreferences. If a download is
      * already in progress, do nothing.
      */
-    void resumeAllPendingDownloads() {
+    public void resumeAllPendingDownloads() {
+        if (!DownloadManagerService.hasDownloadManagerService()) return;
         List<DownloadSharedPreferenceEntry> entries = mDownloadSharedPreferenceHelper.getEntries();
         for (int i = 0; i < entries.size(); ++i) {
             DownloadSharedPreferenceEntry entry = entries.get(i);
-            if (!canResumeDownload(ContextUtils.getApplicationContext(), entry)) continue;
+            if (!canResumeDownload(mContext, entry)) continue;
             if (mDownloadsInProgress.contains(entry.id)) continue;
 
-            Intent intent = new Intent();
-            intent.setAction(ACTION_DOWNLOAD_RESUME);
-            intent.putExtra(EXTRA_DOWNLOAD_CONTENTID_ID, entry.id.id);
-            intent.putExtra(EXTRA_DOWNLOAD_CONTENTID_NAMESPACE, entry.id.namespace);
-
-            resumeDownload(intent);
+            notifyDownloadPending(entry.id, entry.fileName, entry.isOffTheRecord,
+                    entry.canDownloadWhileMetered, entry.isTransient, null);
+            DownloadServiceDelegate downloadServiceDelegate = getServiceDelegate(entry.id);
+            downloadServiceDelegate.resumeDownload(entry.id, entry.buildDownloadItem(), false);
+            downloadServiceDelegate.destroyServiceDelegate();
         }
     }
 
-    @VisibleForTesting
-    void resumeDownload(Intent intent) {
-        DownloadBroadcastManager.startDownloadBroadcastManager(
-                ContextUtils.getApplicationContext(), intent);
-    }
-
     /**
      * Return the notification ID for the given download {@link ContentId}.
      * @param id the {@link ContentId} of the download.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService2.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService2.java
new file mode 100644
index 0000000..46771ed3
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService2.java
@@ -0,0 +1,531 @@
+// 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.
+
+package org.chromium.chrome.browser.download;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.drawable.shapes.OvalShape;
+import android.text.TextUtils;
+
+import org.chromium.base.ApiCompatibilityUtils;
+import org.chromium.base.ContextUtils;
+import org.chromium.base.VisibleForTesting;
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.notifications.NotificationUmaTracker;
+import org.chromium.chrome.browser.notifications.channels.ChannelDefinitions;
+import org.chromium.components.offline_items_collection.ContentId;
+import org.chromium.components.offline_items_collection.LegacyHelpers;
+import org.chromium.components.offline_items_collection.OfflineItem.Progress;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Central director for updates related to downloads and notifications.
+ *  - Receive updates about downloads through SystemDownloadNotifier (notifyDownloadPaused, etc).
+ *  - Create notifications for downloads using DownloadNotificationFactory.
+ *  - Update DownloadForegroundServiceManager about downloads, allowing it to start/stop service.
+ */
+public class DownloadNotificationService2 {
+    static final String EXTRA_DOWNLOAD_CONTENTID_ID =
+            "org.chromium.chrome.browser.download.DownloadContentId_Id";
+    static final String EXTRA_DOWNLOAD_CONTENTID_NAMESPACE =
+            "org.chromium.chrome.browser.download.DownloadContentId_Namespace";
+    static final String EXTRA_DOWNLOAD_FILE_PATH = "DownloadFilePath";
+    static final String EXTRA_IS_SUPPORTED_MIME_TYPE = "IsSupportedMimeType";
+    static final String EXTRA_IS_OFF_THE_RECORD =
+            "org.chromium.chrome.browser.download.IS_OFF_THE_RECORD";
+
+    public static final String ACTION_DOWNLOAD_CANCEL =
+            "org.chromium.chrome.browser.download.DOWNLOAD_CANCEL";
+    public static final String ACTION_DOWNLOAD_PAUSE =
+            "org.chromium.chrome.browser.download.DOWNLOAD_PAUSE";
+    public static final String ACTION_DOWNLOAD_RESUME =
+            "org.chromium.chrome.browser.download.DOWNLOAD_RESUME";
+    public static final String ACTION_DOWNLOAD_OPEN =
+            "org.chromium.chrome.browser.download.DOWNLOAD_OPEN";
+
+    public static final String NOTIFICATION_NAMESPACE = "DownloadNotificationService";
+
+    public static final String EXTRA_NOTIFICATION_BUNDLE_ICON_ID =
+            "Chrome.NotificationBundleIconIdExtra";
+    /** Notification Id starting value, to avoid conflicts from IDs used in prior versions. */
+    private static final int STARTING_NOTIFICATION_ID = 1000000;
+
+    private static final String KEY_NEXT_DOWNLOAD_NOTIFICATION_ID = "NextDownloadNotificationId";
+
+    @VisibleForTesting
+    final List<ContentId> mDownloadsInProgress = new ArrayList<ContentId>();
+
+    private NotificationManager mNotificationManager;
+    private SharedPreferences mSharedPrefs;
+    private int mNextNotificationId;
+    private Bitmap mDownloadSuccessLargeIcon;
+    private DownloadSharedPreferenceHelper mDownloadSharedPreferenceHelper;
+    private DownloadForegroundServiceManager mDownloadForegroundServiceManager;
+
+    private static class LazyHolder {
+        private static final DownloadNotificationService2 INSTANCE =
+                new DownloadNotificationService2();
+    }
+
+    /**
+     * Creates DownloadNotificationService.
+     */
+    public static DownloadNotificationService2 getInstance() {
+        return LazyHolder.INSTANCE;
+    }
+
+    @VisibleForTesting
+    DownloadNotificationService2() {
+        mNotificationManager =
+                (NotificationManager) ContextUtils.getApplicationContext().getSystemService(
+                        Context.NOTIFICATION_SERVICE);
+        mSharedPrefs = ContextUtils.getAppSharedPreferences();
+        mDownloadSharedPreferenceHelper = DownloadSharedPreferenceHelper.getInstance();
+        mNextNotificationId =
+                mSharedPrefs.getInt(KEY_NEXT_DOWNLOAD_NOTIFICATION_ID, STARTING_NOTIFICATION_ID);
+        mDownloadForegroundServiceManager = new DownloadForegroundServiceManager();
+    }
+
+    @VisibleForTesting
+    void setDownloadForegroundServiceManager(
+            DownloadForegroundServiceManager downloadForegroundServiceManager) {
+        mDownloadForegroundServiceManager = downloadForegroundServiceManager;
+    }
+
+    // TODO(jming): Figure out resumption logic (http://crbug.com/755771)
+    //  - onDestroy/rescheduleDownloads/updateNotificationsForShutdown
+    //  - onTaskRemoved/cancelOffTheRecordDownloads
+    //  - onStartCommand/null Intent
+    //  - updateResumptionAttemptLeft / etc.
+
+    /**
+     * @return Whether or not there are any current resumable downloads being tracked.  These
+     *         tracked downloads may not currently be showing notifications.
+     */
+    static boolean isTrackingResumableDownloads(Context context) {
+        List<DownloadSharedPreferenceEntry> entries =
+                DownloadSharedPreferenceHelper.getInstance().getEntries();
+        for (DownloadSharedPreferenceEntry entry : entries) {
+            if (canResumeDownload(context, entry)) return true;
+        }
+        return false;
+    }
+
+    /**
+     * Track in-progress downloads here.
+     * @param id The {@link ContentId} of the download that has been started and should be tracked.
+     */
+    private void startTrackingInProgressDownload(ContentId id) {
+        if (!mDownloadsInProgress.contains(id)) mDownloadsInProgress.add(id);
+    }
+
+    /**
+     * Stop tracking the download represented by {@code id}.
+     * @param id                  The {@link ContentId} of the download that has been paused or
+     *                            canceled and shouldn't be tracked.
+     */
+    private void stopTrackingInProgressDownload(ContentId id) {
+        mDownloadsInProgress.remove(id);
+    }
+
+    /**
+     * Adds or updates an in-progress download notification.
+     * @param id                      The {@link ContentId} of the download.
+     * @param fileName                File name of the download.
+     * @param progress                The current download progress.
+     * @param bytesReceived           Total number of bytes received.
+     * @param timeRemainingInMillis   Remaining download time in milliseconds.
+     * @param startTime               Time when download started.
+     * @param isOffTheRecord          Whether the download is off the record.
+     * @param canDownloadWhileMetered Whether the download can happen in metered network.
+     * @param isTransient             Whether or not clicking on the download should launch
+     *                                downloads home.
+     * @param icon                    A {@link Bitmap} to be used as the large icon for display.
+     */
+    @VisibleForTesting
+    public void notifyDownloadProgress(ContentId id, String fileName, Progress progress,
+            long bytesReceived, long timeRemainingInMillis, long startTime, boolean isOffTheRecord,
+            boolean canDownloadWhileMetered, boolean isTransient, Bitmap icon) {
+        updateActiveDownloadNotification(id, fileName, progress, timeRemainingInMillis, startTime,
+                isOffTheRecord, canDownloadWhileMetered, false, isTransient, icon, false);
+    }
+
+    /**
+     * Adds or updates a pending download notification.
+     * @param id                      The {@link ContentId} of the download.
+     * @param fileName                File name of the download.
+     * @param isOffTheRecord          Whether the download is off the record.
+     * @param canDownloadWhileMetered Whether the download can happen in metered network.
+     * @param isTransient             Whether or not clicking on the download should launch
+     *                                downloads home.
+     * @param icon                    A {@link Bitmap} to be used as the large icon for display.
+     */
+    void notifyDownloadPending(ContentId id, String fileName, boolean isOffTheRecord,
+            boolean canDownloadWhileMetered, boolean isTransient, Bitmap icon,
+            boolean hasUserGesture) {
+        updateActiveDownloadNotification(id, fileName, Progress.createIndeterminateProgress(), 0, 0,
+                isOffTheRecord, canDownloadWhileMetered, true, isTransient, icon, hasUserGesture);
+    }
+
+    /**
+     * Helper method to update the notification for an active download, the download is either in
+     * progress or pending.
+     * @param id                      The {@link ContentId} of the download.
+     * @param fileName                File name of the download.
+     * @param progress                The current download progress.
+     * @param timeRemainingInMillis   Remaining download time in milliseconds or -1 if it is
+     *                                unknown.
+     * @param startTime               Time when download started.
+     * @param isOffTheRecord          Whether the download is off the record.
+     * @param canDownloadWhileMetered Whether the download can happen in metered network.
+     * @param isDownloadPending       Whether the download is pending.
+     * @param isTransient             Whether or not clicking on the download should launch
+     *                                downloads home.
+     * @param icon                    A {@link Bitmap} to be used as the large icon for display.
+     */
+    private void updateActiveDownloadNotification(ContentId id, String fileName, Progress progress,
+            long timeRemainingInMillis, long startTime, boolean isOffTheRecord,
+            boolean canDownloadWhileMetered, boolean isDownloadPending, boolean isTransient,
+            Bitmap icon, boolean hasUserGesture) {
+        int notificationId = getNotificationId(id);
+        Context context = ContextUtils.getApplicationContext();
+
+        DownloadUpdate downloadUpdate = new DownloadUpdate.Builder()
+                                                .setContentId(id)
+                                                .setFileName(fileName)
+                                                .setProgress(progress)
+                                                .setTimeRemainingInMillis(timeRemainingInMillis)
+                                                .setStartTime(startTime)
+                                                .setIsOffTheRecord(isOffTheRecord)
+                                                .setIsDownloadPending(isDownloadPending)
+                                                .setIsTransient(isTransient)
+                                                .setIcon(icon)
+                                                .setNotificationId(notificationId)
+                                                .build();
+        Notification notification = DownloadNotificationFactory.buildNotification(
+                context, DownloadNotificationFactory.DownloadStatus.IN_PROGRESS, downloadUpdate);
+
+        // If called from DownloadBroadcastManager, only update notification, not tracking.
+        if (hasUserGesture) {
+            updateNotification(notificationId, notification);
+            return;
+        }
+
+        updateNotification(notificationId, notification, id,
+                new DownloadSharedPreferenceEntry(id, notificationId, isOffTheRecord,
+                        canDownloadWhileMetered, fileName, true, isTransient));
+        // TODO(jming): do we want to handle the pending option in a different manner?
+        mDownloadForegroundServiceManager.updateDownloadStatus(context,
+                DownloadForegroundServiceManager.DownloadStatus.IN_PROGRESS, notificationId,
+                notification);
+
+        startTrackingInProgressDownload(id);
+    }
+
+    public void cancelNotification(int notificationId) {
+        mNotificationManager.cancel(NOTIFICATION_NAMESPACE, notificationId);
+    }
+
+    /**
+     * Removes a download notification and all associated tracking.  This method relies on the
+     * caller to provide the notification id, which is useful in the case where the internal
+     * tracking doesn't exist (e.g. in the case of a successful download, where we show the download
+     * completed notification and remove our internal state tracking).
+     * @param notificationId Notification ID of the download
+     * @param id The {@link ContentId} of the download.
+     */
+    public void cancelNotification(int notificationId, ContentId id) {
+        cancelNotification(notificationId);
+        mDownloadSharedPreferenceHelper.removeSharedPreferenceEntry(id);
+
+        stopTrackingInProgressDownload(id);
+    }
+
+    /**
+     * Called when a download is canceled.  This method uses internal tracking to try to find the
+     * notification id to cancel.
+     * @param id The {@link ContentId} of the download.
+     */
+    @VisibleForTesting
+    public void notifyDownloadCanceled(ContentId id, boolean hasUserGesture) {
+        DownloadSharedPreferenceEntry entry =
+                mDownloadSharedPreferenceHelper.getDownloadSharedPreferenceEntry(id);
+        if (entry == null) return;
+
+        // If called from DownloadBroadcastManager, only update notification, not tracking.
+        if (hasUserGesture) {
+            cancelNotification(entry.notificationId);
+            return;
+        }
+
+        cancelNotification(entry.notificationId, id);
+        mDownloadForegroundServiceManager.updateDownloadStatus(ContextUtils.getApplicationContext(),
+                DownloadForegroundServiceManager.DownloadStatus.CANCEL, entry.notificationId, null);
+    }
+
+    /**
+     * Change a download notification to paused state.
+     * @param id              The {@link ContentId} of the download.
+     * @param fileName        File name of the download.
+     * @param isResumable     Whether download can be resumed.
+     * @param isAutoResumable Whether download is can be resumed automatically.
+     * @param isOffTheRecord  Whether the download is off the record.
+     * @param isTransient     Whether or not clicking on the download should launch downloads home.
+     * @param icon            A {@link Bitmap} to be used as the large icon for display.
+     */
+    @VisibleForTesting
+    void notifyDownloadPaused(ContentId id, String fileName, boolean isResumable,
+            boolean isAutoResumable, boolean isOffTheRecord, boolean isTransient, Bitmap icon,
+            boolean hasUserGesture) {
+        DownloadSharedPreferenceEntry entry =
+                mDownloadSharedPreferenceHelper.getDownloadSharedPreferenceEntry(id);
+        if (!isResumable) {
+            notifyDownloadFailed(id, fileName, icon);
+            return;
+        }
+        // If download is already paused, do nothing.
+        if (entry != null && !entry.isAutoResumable) return;
+        boolean canDownloadWhileMetered = entry == null ? false : entry.canDownloadWhileMetered;
+        // If download is interrupted due to network disconnection, show download pending state.
+        if (isAutoResumable) {
+            notifyDownloadPending(id, fileName, isOffTheRecord, canDownloadWhileMetered,
+                    isTransient, icon, hasUserGesture);
+            stopTrackingInProgressDownload(id);
+            return;
+        }
+        int notificationId = entry == null ? getNotificationId(id) : entry.notificationId;
+        Context context = ContextUtils.getApplicationContext();
+
+        DownloadUpdate downloadUpdate = new DownloadUpdate.Builder()
+                                                .setContentId(id)
+                                                .setFileName(fileName)
+                                                .setIsOffTheRecord(isOffTheRecord)
+                                                .setIsTransient(isTransient)
+                                                .setIcon(icon)
+                                                .setNotificationId(notificationId)
+                                                .build();
+
+        Notification notification = DownloadNotificationFactory.buildNotification(
+                context, DownloadNotificationFactory.DownloadStatus.PAUSED, downloadUpdate);
+
+        updateNotification(notificationId, notification, id,
+                new DownloadSharedPreferenceEntry(id, notificationId, isOffTheRecord,
+                        canDownloadWhileMetered, fileName, isAutoResumable, isTransient));
+
+        // If called from DownloadBroadcastManager, only update notification, not tracking.
+        if (hasUserGesture) {
+            updateNotification(notificationId, notification);
+            return;
+        }
+
+        mDownloadForegroundServiceManager.updateDownloadStatus(context,
+                DownloadForegroundServiceManager.DownloadStatus.PAUSE, notificationId,
+                notification);
+
+        stopTrackingInProgressDownload(id);
+    }
+
+    /**
+     * Add a download successful notification.
+     * @param id                  The {@link ContentId} of the download.
+     * @param filePath            Full path to the download.
+     * @param fileName            Filename of the download.
+     * @param systemDownloadId    Download ID assigned by system DownloadManager.
+     * @param isSupportedMimeType Whether the MIME type can be viewed inside browser.
+     * @param isOpenable          Whether or not this download can be opened.
+     * @param icon                A {@link Bitmap} to be used as the large icon for display.
+     * @param originalUrl         The original url of the downloaded file.
+     * @param referrer            Referrer of the downloaded file.
+     * @return                    ID of the successful download notification. Used for removing the
+     *                            notification when user click on the snackbar.
+     */
+    @VisibleForTesting
+    public int notifyDownloadSuccessful(ContentId id, String filePath, String fileName,
+            long systemDownloadId, boolean isOffTheRecord, boolean isSupportedMimeType,
+            boolean isOpenable, Bitmap icon, String originalUrl, String referrer) {
+        Context context = ContextUtils.getApplicationContext();
+        int notificationId = getNotificationId(id);
+        if (icon == null && mDownloadSuccessLargeIcon == null) {
+            Bitmap bitmap =
+                    BitmapFactory.decodeResource(context.getResources(), R.drawable.offline_pin);
+            mDownloadSuccessLargeIcon = getLargeNotificationIcon(bitmap);
+        }
+        if (icon == null) icon = mDownloadSuccessLargeIcon;
+
+        DownloadUpdate downloadUpdate = new DownloadUpdate.Builder()
+                                                .setContentId(id)
+                                                .setFileName(fileName)
+                                                .setFilePath(filePath)
+                                                .setSystemDownload(systemDownloadId)
+                                                .setIsOffTheRecord(isOffTheRecord)
+                                                .setIsSupportedMimeType(isSupportedMimeType)
+                                                .setIsOpenable(isOpenable)
+                                                .setIcon(icon)
+                                                .setNotificationId(notificationId)
+                                                .setOriginalUrl(originalUrl)
+                                                .setReferrer(referrer)
+                                                .build();
+        Notification notification = DownloadNotificationFactory.buildNotification(
+                context, DownloadNotificationFactory.DownloadStatus.SUCCESSFUL, downloadUpdate);
+
+        updateNotification(notificationId, notification, id, null);
+        mDownloadForegroundServiceManager.updateDownloadStatus(context,
+                DownloadForegroundServiceManager.DownloadStatus.COMPLETE, notificationId,
+                notification);
+        stopTrackingInProgressDownload(id);
+        return notificationId;
+    }
+
+    /**
+     * Add a download failed notification.
+     * @param id       The {@link ContentId} of the download.
+     * @param fileName Filename of the download.
+     * @param icon     A {@link Bitmap} to be used as the large icon for display.
+     */
+    @VisibleForTesting
+    public void notifyDownloadFailed(ContentId id, String fileName, Bitmap icon) {
+        // If the download is not in history db, fileName could be empty. Get it from
+        // SharedPreferences.
+        if (TextUtils.isEmpty(fileName)) {
+            DownloadSharedPreferenceEntry entry =
+                    mDownloadSharedPreferenceHelper.getDownloadSharedPreferenceEntry(id);
+            if (entry == null) return;
+            fileName = entry.fileName;
+        }
+
+        int notificationId = getNotificationId(id);
+        Context context = ContextUtils.getApplicationContext();
+
+        DownloadUpdate downloadUpdate = new DownloadUpdate.Builder()
+                                                .setContentId(id)
+                                                .setFileName(fileName)
+                                                .setIcon(icon)
+                                                .build();
+        Notification notification = DownloadNotificationFactory.buildNotification(
+                context, DownloadNotificationFactory.DownloadStatus.FAILED, downloadUpdate);
+
+        updateNotification(notificationId, notification, id, null);
+        mDownloadForegroundServiceManager.updateDownloadStatus(context,
+                DownloadForegroundServiceManager.DownloadStatus.FAIL, notificationId, notification);
+
+        stopTrackingInProgressDownload(id);
+    }
+
+    private Bitmap getLargeNotificationIcon(Bitmap bitmap) {
+        Resources resources = ContextUtils.getApplicationContext().getResources();
+        int height = (int) resources.getDimension(android.R.dimen.notification_large_icon_height);
+        int width = (int) resources.getDimension(android.R.dimen.notification_large_icon_width);
+        final OvalShape circle = new OvalShape();
+        circle.resize(width, height);
+        final Paint paint = new Paint();
+        paint.setColor(ApiCompatibilityUtils.getColor(resources, R.color.google_blue_grey_500));
+
+        final Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(result);
+        circle.draw(canvas, paint);
+        float leftOffset = (width - bitmap.getWidth()) / 2f;
+        float topOffset = (height - bitmap.getHeight()) / 2f;
+        if (leftOffset >= 0 && topOffset >= 0) {
+            canvas.drawBitmap(bitmap, leftOffset, topOffset, null);
+        } else {
+            // Scale down the icon into the notification icon dimensions
+            canvas.drawBitmap(bitmap, new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()),
+                    new Rect(0, 0, width, height), null);
+        }
+        return result;
+    }
+
+    @VisibleForTesting
+    void updateNotification(int id, Notification notification) {
+        mNotificationManager.notify(NOTIFICATION_NAMESPACE, id, notification);
+    }
+
+    private void updateNotification(int notificationId, Notification notification, ContentId id,
+            DownloadSharedPreferenceEntry entry) {
+        updateNotification(notificationId, notification);
+        trackNotificationUma(id);
+
+        if (entry != null) {
+            mDownloadSharedPreferenceHelper.addOrReplaceSharedPreferenceEntry(entry);
+        } else {
+            mDownloadSharedPreferenceHelper.removeSharedPreferenceEntry(id);
+        }
+    }
+
+    private void trackNotificationUma(ContentId id) {
+        // Check if we already have an entry in the DownloadSharedPreferenceHelper.  This is a
+        // reasonable indicator for whether or not a notification is already showing (or at least if
+        // we had built one for this download before.
+        if (mDownloadSharedPreferenceHelper.hasEntry(id)) return;
+        NotificationUmaTracker.getInstance().onNotificationShown(
+                LegacyHelpers.isLegacyOfflinePage(id) ? NotificationUmaTracker.DOWNLOAD_PAGES
+                                                      : NotificationUmaTracker.DOWNLOAD_FILES,
+                ChannelDefinitions.CHANNEL_ID_DOWNLOADS);
+    }
+
+    private static boolean canResumeDownload(Context context, DownloadSharedPreferenceEntry entry) {
+        if (entry == null) return false;
+        if (!entry.isAutoResumable) return false;
+
+        boolean isNetworkMetered = DownloadManagerService.isActiveNetworkMetered(context);
+        return entry.canDownloadWhileMetered || !isNetworkMetered;
+    }
+
+    /**
+     * Resumes all pending downloads from SharedPreferences. If a download is
+     * already in progress, do nothing.
+     */
+    void resumeAllPendingDownloads() {
+        Context context = ContextUtils.getApplicationContext();
+        List<DownloadSharedPreferenceEntry> entries = mDownloadSharedPreferenceHelper.getEntries();
+        for (int i = 0; i < entries.size(); ++i) {
+            DownloadSharedPreferenceEntry entry = entries.get(i);
+            if (!canResumeDownload(context, entry)) continue;
+            if (mDownloadsInProgress.contains(entry.id)) continue;
+
+            Intent intent = new Intent();
+            intent.setAction(ACTION_DOWNLOAD_RESUME);
+            intent.putExtra(EXTRA_DOWNLOAD_CONTENTID_ID, entry.id.id);
+            intent.putExtra(EXTRA_DOWNLOAD_CONTENTID_NAMESPACE, entry.id.namespace);
+
+            resumeDownload(intent);
+        }
+    }
+
+    @VisibleForTesting
+    void resumeDownload(Intent intent) {
+        DownloadBroadcastManager.startDownloadBroadcastManager(
+                ContextUtils.getApplicationContext(), intent);
+    }
+
+    /**
+     * Return the notification ID for the given download {@link ContentId}.
+     * @param id the {@link ContentId} of the download.
+     * @return notification ID to be used.
+     */
+    private int getNotificationId(ContentId id) {
+        DownloadSharedPreferenceEntry entry =
+                mDownloadSharedPreferenceHelper.getDownloadSharedPreferenceEntry(id);
+        if (entry != null) return entry.notificationId;
+        int notificationId = mNextNotificationId;
+        mNextNotificationId = mNextNotificationId == Integer.MAX_VALUE ? STARTING_NOTIFICATION_ID
+                                                                       : mNextNotificationId + 1;
+        SharedPreferences.Editor editor = mSharedPrefs.edit();
+        editor.putInt(KEY_NEXT_DOWNLOAD_NOTIFICATION_ID, mNextNotificationId);
+        editor.apply();
+        return notificationId;
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadResumptionScheduler.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadResumptionScheduler.java
index 93fe3b0..b584fb2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadResumptionScheduler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadResumptionScheduler.java
@@ -6,6 +6,7 @@
 
 import android.annotation.SuppressLint;
 import android.content.Context;
+import android.content.Intent;
 
 import com.google.android.gms.gcm.GcmNetworkManager;
 import com.google.android.gms.gcm.OneoffTask;
@@ -17,14 +18,13 @@
 import org.chromium.chrome.browser.ChromeBackgroundService;
 
 /**
- * Class for scheduling download resumption tasks.
+ * Class for scheduing download resumption tasks.
  */
 public class DownloadResumptionScheduler {
     public static final String TASK_TAG = "DownloadResumption";
     private static final String TAG = "DownloadScheduler";
     private static final int ONE_DAY_IN_SECONDS = 24 * 60 * 60;
     private final Context mContext;
-    private final DownloadNotificationService mDownloadNotificationService;
     @SuppressLint("StaticFieldLeak")
     private static DownloadResumptionScheduler sDownloadResumptionScheduler;
 
@@ -39,12 +39,11 @@
 
     protected DownloadResumptionScheduler(Context context) {
         mContext = context;
-        mDownloadNotificationService = DownloadNotificationService.getInstance();
     }
 
     /**
      * For tests only: sets the DownloadResumptionScheduler.
-     * @param scheduler An instance of DownloadResumptionScheduler.
+     * @param service An instance of DownloadResumptionScheduler.
      */
     @VisibleForTesting
     public static void setDownloadResumptionScheduler(DownloadResumptionScheduler scheduler) {
@@ -86,6 +85,9 @@
      * Start browser process and resumes all interrupted downloads.
      */
     public void handleDownloadResumption() {
-        mDownloadNotificationService.resumeAllPendingDownloads();
+        // Fire an intent to the DownloadNotificationService so that it will handle download
+        // resumption.
+        Intent intent = new Intent(DownloadNotificationService.ACTION_DOWNLOAD_RESUME_ALL);
+        DownloadNotificationService.startDownloadNotificationService(mContext, intent);
     }
 }
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadResumptionScheduler2.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadResumptionScheduler2.java
new file mode 100644
index 0000000..3537e3d
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadResumptionScheduler2.java
@@ -0,0 +1,91 @@
+// 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.
+
+package org.chromium.chrome.browser.download;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+
+import com.google.android.gms.gcm.GcmNetworkManager;
+import com.google.android.gms.gcm.OneoffTask;
+import com.google.android.gms.gcm.Task;
+
+import org.chromium.base.Log;
+import org.chromium.base.VisibleForTesting;
+import org.chromium.base.annotations.SuppressFBWarnings;
+import org.chromium.chrome.browser.ChromeBackgroundService;
+
+/**
+ * Class for scheduling download resumption tasks.
+ */
+public class DownloadResumptionScheduler2 {
+    public static final String TASK_TAG = "DownloadResumption";
+    private static final String TAG = "DownloadScheduler";
+    private static final int ONE_DAY_IN_SECONDS = 24 * 60 * 60;
+    private final Context mContext;
+    private final DownloadNotificationService2 mDownloadNotificationService;
+    @SuppressLint("StaticFieldLeak")
+    private static DownloadResumptionScheduler2 sDownloadResumptionScheduler;
+
+    @SuppressFBWarnings("LI_LAZY_INIT")
+    public static DownloadResumptionScheduler2 getDownloadResumptionScheduler(Context context) {
+        assert context == context.getApplicationContext();
+        if (sDownloadResumptionScheduler == null) {
+            sDownloadResumptionScheduler = new DownloadResumptionScheduler2(context);
+        }
+        return sDownloadResumptionScheduler;
+    }
+
+    protected DownloadResumptionScheduler2(Context context) {
+        mContext = context;
+        mDownloadNotificationService = DownloadNotificationService2.getInstance();
+    }
+
+    /**
+     * For tests only: sets the DownloadResumptionScheduler.
+     * @param scheduler An instance of DownloadResumptionScheduler.
+     */
+    @VisibleForTesting
+    public static void setDownloadResumptionScheduler(DownloadResumptionScheduler2 scheduler) {
+        sDownloadResumptionScheduler = scheduler;
+    }
+
+    /**
+     * Schedules a future task to start download resumption.
+     * @param allowMeteredConnection Whether download resumption can start if connection is metered.
+     */
+    public void schedule(boolean allowMeteredConnection) {
+        GcmNetworkManager gcmNetworkManager = GcmNetworkManager.getInstance(mContext);
+        int networkType = allowMeteredConnection ? Task.NETWORK_STATE_CONNECTED
+                                                 : Task.NETWORK_STATE_UNMETERED;
+        OneoffTask task = new OneoffTask.Builder()
+                                  .setService(ChromeBackgroundService.class)
+                                  .setExecutionWindow(0, ONE_DAY_IN_SECONDS)
+                                  .setTag(TASK_TAG)
+                                  .setUpdateCurrent(true)
+                                  .setRequiredNetwork(networkType)
+                                  .setRequiresCharging(false)
+                                  .build();
+        try {
+            gcmNetworkManager.schedule(task);
+        } catch (IllegalArgumentException e) {
+            Log.e(TAG, "unable to schedule resumption task.", e);
+        }
+    }
+
+    /**
+     * Cancels a download resumption task if it is scheduled.
+     */
+    public void cancelTask() {
+        GcmNetworkManager gcmNetworkManager = GcmNetworkManager.getInstance(mContext);
+        gcmNetworkManager.cancelTask(TASK_TAG, ChromeBackgroundService.class);
+    }
+
+    /**
+     * Start browser process and resumes all interrupted downloads.
+     */
+    public void handleDownloadResumption() {
+        mDownloadNotificationService.resumeAllPendingDownloads();
+    }
+}
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier.java b/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier.java
index e4de00e..fb96ac6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier.java
@@ -4,18 +4,69 @@
 
 package org.chromium.chrome.browser.download;
 
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
 
+import org.chromium.base.Log;
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.VisibleForTesting;
+import org.chromium.chrome.browser.download.DownloadNotificationService.Observer;
 import org.chromium.components.offline_items_collection.ContentId;
 
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
 /**
  * DownloadNotifier implementation that creates and updates download notifications.
  * This class creates the {@link DownloadNotificationService} when needed, and binds
  * to the latter to issue calls to show and update notifications.
  */
-public class SystemDownloadNotifier implements DownloadNotifier {
+public class SystemDownloadNotifier implements DownloadNotifier, Observer {
+    private static final String TAG = "DownloadNotifier";
+    private static final int DOWNLOAD_NOTIFICATION_TYPE_PROGRESS = 0;
+    private static final int DOWNLOAD_NOTIFICATION_TYPE_SUCCESS = 1;
+    private static final int DOWNLOAD_NOTIFICATION_TYPE_FAILURE = 2;
+    private static final int DOWNLOAD_NOTIFICATION_TYPE_CANCEL = 3;
+    private static final int DOWNLOAD_NOTIFICATION_TYPE_RESUME_ALL = 4;
+    private static final int DOWNLOAD_NOTIFICATION_TYPE_PAUSE = 5;
+    private static final int DOWNLOAD_NOTIFICATION_TYPE_INTERRUPT = 6;
+    private static final int DOWNLOAD_NOTIFICATION_TYPE_REMOVE_NOTIFICATION = 7;
+
     private final Context mApplicationContext;
-    private final DownloadNotificationService mDownloadNotificationService;
+    @Nullable
+    private DownloadNotificationService mBoundService;
+    private Set<String> mActiveDownloads = new HashSet<String>();
+    private ArrayList<PendingNotificationInfo> mPendingNotifications =
+            new ArrayList<PendingNotificationInfo>();
+
+    private boolean mIsServiceBound;
+
+    /**
+     * Pending download notifications to be posted.
+     */
+    static class PendingNotificationInfo {
+        // Pending download notifications to be posted.
+        public final int type;
+        public final DownloadInfo downloadInfo;
+        public long startTime;
+        public boolean isAutoResumable;
+        public boolean canDownloadWhileMetered;
+        public boolean canResolve;
+        public long systemDownloadId;
+        public boolean isSupportedMimeType;
+        public int notificationId;
+
+        public PendingNotificationInfo(int type, DownloadInfo downloadInfo) {
+            this.type = type;
+            this.downloadInfo = downloadInfo;
+        }
+    }
 
     /**
      * Constructor.
@@ -23,64 +74,245 @@
      */
     public SystemDownloadNotifier(Context context) {
         mApplicationContext = context.getApplicationContext();
-        mDownloadNotificationService = DownloadNotificationService.getInstance();
+    }
+
+    /**
+     * Object to receive information as the service is started and stopped.
+     */
+    private final ServiceConnection mConnection = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName className, IBinder service) {
+            if (!(service instanceof DownloadNotificationService.LocalBinder)) {
+                Log.w(TAG,
+                        "Not from DownloadNotificationService, do not connect."
+                                + " Component name: " + className);
+                assert false;
+                return;
+            }
+            mBoundService = ((DownloadNotificationService.LocalBinder) service).getService();
+            mBoundService.addObserver(SystemDownloadNotifier.this);
+            // updateDownloadNotification() may leave some outstanding notifications
+            // before the service is connected, handle them now.
+            handlePendingNotifications();
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName className) {}
+    };
+
+    /**
+     * For tests only: sets the DownloadNotificationService.
+     * @param service An instance of DownloadNotificationService.
+     */
+    @VisibleForTesting
+    void setDownloadNotificationService(DownloadNotificationService service) {
+        mBoundService = service;
+    }
+
+    /**
+     * Handles all the pending notifications that hasn't been processed.
+     */
+    @VisibleForTesting
+    void handlePendingNotifications() {
+        if (mPendingNotifications.isEmpty()) return;
+        for (int i = 0; i < mPendingNotifications.size(); i++) {
+            updateDownloadNotification(
+                    mPendingNotifications.get(i), i == mPendingNotifications.size() - 1);
+        }
+        mPendingNotifications.clear();
+    }
+
+    /**
+     * Starts and binds to the download notification service if needed.
+     */
+    private void startAndBindToServiceIfNeeded() {
+        if (mIsServiceBound) return;
+        startAndBindService();
+        mIsServiceBound = true;
+    }
+
+    /**
+     * Stops the download notification service if there are no download in progress.
+     */
+    private void unbindServiceIfNeeded() {
+        if (!mActiveDownloads.isEmpty() || !mIsServiceBound) return;
+        if (mBoundService != null) mBoundService.removeObserver(this);
+        unbindService();
+        mBoundService = null;
+        mIsServiceBound = false;
+    }
+
+    @VisibleForTesting
+    void startAndBindService() {
+        DownloadNotificationService.startDownloadNotificationService(mApplicationContext, null);
+        mApplicationContext.bindService(
+                new Intent(mApplicationContext, DownloadNotificationService.class), mConnection,
+                Context.BIND_AUTO_CREATE);
+    }
+
+    @VisibleForTesting
+    void unbindService() {
+        mApplicationContext.unbindService(mConnection);
+    }
+
+    @Override
+    public void onDownloadCanceled(ContentId id) {
+        mActiveDownloads.remove(id.id);
+        if (mActiveDownloads.isEmpty()) unbindServiceIfNeeded();
     }
 
     @Override
     public void notifyDownloadCanceled(ContentId id) {
-        mDownloadNotificationService.notifyDownloadCanceled(id, false);
+        DownloadInfo downloadInfo = new DownloadInfo.Builder().setContentId(id).build();
+        updateDownloadNotification(
+                new PendingNotificationInfo(DOWNLOAD_NOTIFICATION_TYPE_CANCEL, downloadInfo), true);
     }
 
     @Override
-    public void notifyDownloadSuccessful(DownloadInfo info, long systemDownloadId,
+    public void notifyDownloadSuccessful(DownloadInfo downloadInfo, long systemDownloadId,
             boolean canResolve, boolean isSupportedMimeType) {
-        final int notificationId = mDownloadNotificationService.notifyDownloadSuccessful(
-                info.getContentId(), info.getFilePath(), info.getFileName(), systemDownloadId,
-                info.isOffTheRecord(), isSupportedMimeType, info.getIsOpenable(), info.getIcon(),
-                info.getOriginalUrl(), info.getReferrer());
-
-        if (info.getIsOpenable()) {
-            DownloadManagerService.getDownloadManagerService().onSuccessNotificationShown(
-                    info, canResolve, notificationId, systemDownloadId);
-        }
+        PendingNotificationInfo info =
+                new PendingNotificationInfo(DOWNLOAD_NOTIFICATION_TYPE_SUCCESS, downloadInfo);
+        info.canResolve = canResolve;
+        info.systemDownloadId = systemDownloadId;
+        info.isSupportedMimeType = isSupportedMimeType;
+        updateDownloadNotification(info, true);
     }
 
     @Override
-    public void notifyDownloadFailed(DownloadInfo info) {
-        mDownloadNotificationService.notifyDownloadFailed(
-                info.getContentId(), info.getFileName(), info.getIcon());
+    public void notifyDownloadFailed(DownloadInfo downloadInfo) {
+        updateDownloadNotification(
+                new PendingNotificationInfo(DOWNLOAD_NOTIFICATION_TYPE_FAILURE, downloadInfo),
+                true);
     }
 
     @Override
     public void notifyDownloadProgress(
-            DownloadInfo info, long startTime, boolean canDownloadWhileMetered) {
-        mDownloadNotificationService.notifyDownloadProgress(info.getContentId(), info.getFileName(),
-                info.getProgress(), info.getBytesReceived(), info.getTimeRemainingInMillis(),
-                startTime, info.isOffTheRecord(), canDownloadWhileMetered, info.getIsTransient(),
-                info.getIcon());
+            DownloadInfo downloadInfo, long startTime, boolean canDownloadWhileMetered) {
+        PendingNotificationInfo info =
+                new PendingNotificationInfo(DOWNLOAD_NOTIFICATION_TYPE_PROGRESS, downloadInfo);
+        info.startTime = startTime;
+        info.canDownloadWhileMetered = canDownloadWhileMetered;
+        updateDownloadNotification(info, true);
     }
 
     @Override
-    public void notifyDownloadPaused(DownloadInfo info) {
-        mDownloadNotificationService.notifyDownloadPaused(info.getContentId(), info.getFileName(),
-                true, false, info.isOffTheRecord(), info.getIsTransient(), info.getIcon(), false);
+    public void notifyDownloadPaused(DownloadInfo downloadInfo) {
+        PendingNotificationInfo info =
+                new PendingNotificationInfo(DOWNLOAD_NOTIFICATION_TYPE_PAUSE, downloadInfo);
+        updateDownloadNotification(info, true);
     }
 
     @Override
-    public void notifyDownloadInterrupted(DownloadInfo info, boolean isAutoResumable) {
-        mDownloadNotificationService.notifyDownloadPaused(info.getContentId(), info.getFileName(),
-                info.isResumable(), isAutoResumable, info.isOffTheRecord(), info.getIsTransient(),
-                info.getIcon(), false);
+    public void notifyDownloadInterrupted(DownloadInfo downloadInfo, boolean isAutoResumable) {
+        PendingNotificationInfo info =
+                new PendingNotificationInfo(DOWNLOAD_NOTIFICATION_TYPE_INTERRUPT, downloadInfo);
+        info.isAutoResumable = isAutoResumable;
+        updateDownloadNotification(info, true);
     }
 
     @Override
-    public void removeDownloadNotification(int notificationId, DownloadInfo info) {
-        mDownloadNotificationService.cancelNotification(notificationId, info.getContentId());
+    public void removeDownloadNotification(int notificationId, DownloadInfo downloadInfo) {
+        PendingNotificationInfo info = new PendingNotificationInfo(
+                DOWNLOAD_NOTIFICATION_TYPE_REMOVE_NOTIFICATION, downloadInfo);
+        info.notificationId = notificationId;
+        updateDownloadNotification(info, true);
     }
 
     @Override
     public void resumePendingDownloads() {
         if (!DownloadNotificationService.isTrackingResumableDownloads(mApplicationContext)) return;
-        mDownloadNotificationService.resumeAllPendingDownloads();
+
+        updateDownloadNotification(
+                new PendingNotificationInfo(DOWNLOAD_NOTIFICATION_TYPE_RESUME_ALL, null), true);
+    }
+
+    /**
+     * Called when a successful notification is shown.
+     * @param notificationInfo Pending notification information to be handled.
+     * @param notificationId ID of the notification.
+     */
+    @VisibleForTesting
+    void onSuccessNotificationShown(
+            final PendingNotificationInfo notificationInfo, final int notificationId) {
+        if (notificationInfo.downloadInfo == null
+                || !notificationInfo.downloadInfo.getIsOpenable()) {
+            return;
+        }
+        DownloadManagerService.getDownloadManagerService().onSuccessNotificationShown(
+                notificationInfo.downloadInfo, notificationInfo.canResolve, notificationId,
+                notificationInfo.systemDownloadId);
+    }
+
+    /**
+     * Helper method to schedule download notification updates.
+     * @param notificationInfo Pending notification information to be handled.
+     * @param autoRelease Whether or not to allow unbinding the service after processing the action.
+     */
+    @VisibleForTesting
+    void updateDownloadNotification(
+            final PendingNotificationInfo notificationInfo, boolean autoRelease) {
+        assert ThreadUtils.runningOnUiThread();
+        startAndBindToServiceIfNeeded();
+
+        if (mBoundService == null) {
+            mPendingNotifications.add(notificationInfo);
+            return;
+        }
+
+        DownloadInfo info = notificationInfo.downloadInfo;
+        if (notificationInfo.type == DOWNLOAD_NOTIFICATION_TYPE_PROGRESS) {
+            mActiveDownloads.add(info.getDownloadGuid());
+        } else if (notificationInfo.type != DOWNLOAD_NOTIFICATION_TYPE_RESUME_ALL) {
+            mActiveDownloads.remove(info.getDownloadGuid());
+        }
+
+        switch (notificationInfo.type) {
+            case DOWNLOAD_NOTIFICATION_TYPE_PROGRESS:
+                mBoundService.notifyDownloadProgress(info.getContentId(), info.getFileName(),
+                        info.getProgress(), info.getBytesReceived(),
+                        info.getTimeRemainingInMillis(), notificationInfo.startTime,
+                        info.isOffTheRecord(), notificationInfo.canDownloadWhileMetered,
+                        info.getIsTransient(), info.getIcon());
+                break;
+            case DOWNLOAD_NOTIFICATION_TYPE_PAUSE:
+                mBoundService.notifyDownloadPaused(info.getContentId(), info.getFileName(), true,
+                        false, info.isOffTheRecord(), info.getIsTransient(), info.getIcon());
+                break;
+            case DOWNLOAD_NOTIFICATION_TYPE_INTERRUPT:
+                mBoundService.notifyDownloadPaused(info.getContentId(), info.getFileName(),
+                        info.isResumable(), notificationInfo.isAutoResumable, info.isOffTheRecord(),
+                        info.getIsTransient(), info.getIcon());
+                break;
+            case DOWNLOAD_NOTIFICATION_TYPE_SUCCESS:
+                final int notificationId = mBoundService.notifyDownloadSuccessful(
+                        info.getContentId(), info.getFilePath(), info.getFileName(),
+                        notificationInfo.systemDownloadId, info.isOffTheRecord(),
+                        notificationInfo.isSupportedMimeType, info.getIsOpenable(), info.getIcon(),
+                        info.getOriginalUrl(), info.getReferrer());
+                onSuccessNotificationShown(notificationInfo, notificationId);
+                break;
+            case DOWNLOAD_NOTIFICATION_TYPE_FAILURE:
+                mBoundService.notifyDownloadFailed(
+                        info.getContentId(), info.getFileName(), info.getIcon());
+                break;
+            case DOWNLOAD_NOTIFICATION_TYPE_CANCEL:
+                mBoundService.notifyDownloadCanceled(info.getContentId());
+                break;
+            case DOWNLOAD_NOTIFICATION_TYPE_RESUME_ALL:
+                mBoundService.resumeAllPendingDownloads();
+                break;
+            case DOWNLOAD_NOTIFICATION_TYPE_REMOVE_NOTIFICATION:
+                mBoundService.cancelNotification(
+                        notificationInfo.notificationId, info.getContentId());
+                break;
+            default:
+                assert false;
+        }
+
+        // Don't need to expose the notification id to ignore.  Cancel will automatically call this
+        // method as well and pass it in.
+        if (mBoundService != null) mBoundService.hideSummaryNotificationIfNecessary(-1);
+        if (autoRelease) unbindServiceIfNeeded();
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier2.java b/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier2.java
new file mode 100644
index 0000000..131761917
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier2.java
@@ -0,0 +1,86 @@
+// 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.
+
+package org.chromium.chrome.browser.download;
+
+import android.content.Context;
+
+import org.chromium.components.offline_items_collection.ContentId;
+
+/**
+ * DownloadNotifier implementation that creates and updates download notifications.
+ * This class creates the {@link DownloadNotificationService2} when needed, and binds
+ * to the latter to issue calls to show and update notifications.
+ */
+public class SystemDownloadNotifier2 implements DownloadNotifier {
+    private final Context mApplicationContext;
+    private final DownloadNotificationService2 mDownloadNotificationService;
+
+    /**
+     * Constructor.
+     * @param context Application context.
+     */
+    public SystemDownloadNotifier2(Context context) {
+        mApplicationContext = context.getApplicationContext();
+        mDownloadNotificationService = DownloadNotificationService2.getInstance();
+    }
+
+    @Override
+    public void notifyDownloadCanceled(ContentId id) {
+        mDownloadNotificationService.notifyDownloadCanceled(id, false);
+    }
+
+    @Override
+    public void notifyDownloadSuccessful(DownloadInfo info, long systemDownloadId,
+            boolean canResolve, boolean isSupportedMimeType) {
+        final int notificationId = mDownloadNotificationService.notifyDownloadSuccessful(
+                info.getContentId(), info.getFilePath(), info.getFileName(), systemDownloadId,
+                info.isOffTheRecord(), isSupportedMimeType, info.getIsOpenable(), info.getIcon(),
+                info.getOriginalUrl(), info.getReferrer());
+
+        if (info.getIsOpenable()) {
+            DownloadManagerService.getDownloadManagerService().onSuccessNotificationShown(
+                    info, canResolve, notificationId, systemDownloadId);
+        }
+    }
+
+    @Override
+    public void notifyDownloadFailed(DownloadInfo info) {
+        mDownloadNotificationService.notifyDownloadFailed(
+                info.getContentId(), info.getFileName(), info.getIcon());
+    }
+
+    @Override
+    public void notifyDownloadProgress(
+            DownloadInfo info, long startTime, boolean canDownloadWhileMetered) {
+        mDownloadNotificationService.notifyDownloadProgress(info.getContentId(), info.getFileName(),
+                info.getProgress(), info.getBytesReceived(), info.getTimeRemainingInMillis(),
+                startTime, info.isOffTheRecord(), canDownloadWhileMetered, info.getIsTransient(),
+                info.getIcon());
+    }
+
+    @Override
+    public void notifyDownloadPaused(DownloadInfo info) {
+        mDownloadNotificationService.notifyDownloadPaused(info.getContentId(), info.getFileName(),
+                true, false, info.isOffTheRecord(), info.getIsTransient(), info.getIcon(), false);
+    }
+
+    @Override
+    public void notifyDownloadInterrupted(DownloadInfo info, boolean isAutoResumable) {
+        mDownloadNotificationService.notifyDownloadPaused(info.getContentId(), info.getFileName(),
+                info.isResumable(), isAutoResumable, info.isOffTheRecord(), info.getIsTransient(),
+                info.getIcon(), false);
+    }
+
+    @Override
+    public void removeDownloadNotification(int notificationId, DownloadInfo info) {
+        mDownloadNotificationService.cancelNotification(notificationId, info.getContentId());
+    }
+
+    @Override
+    public void resumePendingDownloads() {
+        if (!DownloadNotificationService2.isTrackingResumableDownloads(mApplicationContext)) return;
+        mDownloadNotificationService.resumeAllPendingDownloads();
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/locale/LocaleManager.java b/chrome/android/java/src/org/chromium/chrome/browser/locale/LocaleManager.java
index a9394fc..3b8edcaa 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/locale/LocaleManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/locale/LocaleManager.java
@@ -383,6 +383,14 @@
     }
 
     /**
+     * @return The referral ID to be passed when searching with Mail.RU as the DSE.
+     */
+    @CalledByNative
+    protected String getMailRUReferralId() {
+        return "";
+    }
+
+    /**
      * @return The search engine type for the given url if applicable.
      *         See template_url_prepopulate_data.cc for all values.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/WebApkUma.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/WebApkUma.java
index b0de38a..2f0a4d9a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/metrics/WebApkUma.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/WebApkUma.java
@@ -4,6 +4,14 @@
 
 package org.chromium.chrome.browser.metrics;
 
+import android.content.ContentResolver;
+import android.os.AsyncTask;
+import android.os.Build;
+import android.os.Environment;
+import android.os.StatFs;
+import android.provider.Settings;
+
+import org.chromium.base.ContextUtils;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.webapk.lib.common.WebApkConstants;
 
@@ -141,4 +149,87 @@
         RecordHistogram.recordCustomTimesHistogram("WebApk.LaunchInterval", intervalMs,
                 TimeUnit.HOURS.toMillis(1), TimeUnit.DAYS.toMillis(30), TimeUnit.MILLISECONDS, 50);
     }
+
+    /**
+     * Log the estimated amount of space above the minimum free space threshold that can be used
+     * for WebAPK installation in UMA.
+     */
+    @SuppressWarnings("deprecation")
+    public static void logAvailableSpaceAboveLowSpaceLimitInUMA(boolean installSucceeded) {
+        StatFs partitionStats = new StatFs(Environment.getDataDirectory().getAbsolutePath());
+        long partitionAvailableBytes;
+        long partitionTotalBytes;
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
+            partitionAvailableBytes = partitionStats.getAvailableBytes();
+            partitionTotalBytes = partitionStats.getTotalBytes();
+        } else {
+            long blockSize = partitionStats.getBlockSize(); // deprecated in API level 18.
+            partitionAvailableBytes = blockSize
+                    * (long) partitionStats.getAvailableBlocks(); // deprecated in API level 18.
+            partitionTotalBytes = blockSize * (long) partitionStats.getBlockCount();
+        }
+
+        // ContentResolver APIs are usually heavy, do it in AsyncTask.
+        new AsyncTask<Void, Void, Long>() {
+            @Override
+            protected Long doInBackground(Void... params) {
+                return getLowSpaceLimitBytes(partitionTotalBytes);
+            }
+
+            @Override
+            protected void onPostExecute(Long minimumFreeBytes) {
+                long availableBytesForInstallation = partitionAvailableBytes - minimumFreeBytes;
+                int availableSpaceMb = (int) (availableBytesForInstallation / 1024L / 1024L);
+                // Bound the number to [-1000, 500] and round down to the nearest multiple of 10MB
+                // to avoid exploding the histogram.
+                availableSpaceMb = Math.max(-1000, availableSpaceMb);
+                availableSpaceMb = Math.min(500, availableSpaceMb);
+                availableSpaceMb = availableSpaceMb / 10 * 10;
+
+                if (installSucceeded) {
+                    RecordHistogram.recordSparseSlowlyHistogram(
+                            "WebApk.Install.AvailableSpace.Success", availableSpaceMb);
+                } else {
+                    RecordHistogram.recordSparseSlowlyHistogram(
+                            "WebApk.Install.AvailableSpace.Fail", availableSpaceMb);
+                }
+            }
+        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+    }
+
+    /**
+     * Mirror the system-derived calculation of reserved bytes and return that value.
+     */
+    private static long getLowSpaceLimitBytes(long partitionTotalBytes) {
+        // Copied from android/os/storage/StorageManager.java
+        final int defaultThresholdPercentage = 10;
+        // Copied from android/os/storage/StorageManager.java
+        final long defaultThresholdMaxBytes = 500 * 1024 * 1024;
+        // Copied from android/provider/Settings.java
+        final String sysStorageThresholdPercentage = "sys_storage_threshold_percentage";
+        // Copied from android/provider/Settings.java
+        final String sysStorageThresholdMaxBytes = "sys_storage_threshold_max_bytes";
+
+        ContentResolver resolver = ContextUtils.getApplicationContext().getContentResolver();
+        int minFreePercent = 0;
+        long minFreeBytes = 0;
+
+        // Retrieve platform-appropriate values first
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            minFreePercent = Settings.Global.getInt(
+                    resolver, sysStorageThresholdPercentage, defaultThresholdPercentage);
+            minFreeBytes = Settings.Global.getLong(
+                    resolver, sysStorageThresholdMaxBytes, defaultThresholdMaxBytes);
+        } else {
+            minFreePercent = Settings.Secure.getInt(
+                    resolver, sysStorageThresholdPercentage, defaultThresholdPercentage);
+            minFreeBytes = Settings.Secure.getLong(
+                    resolver, sysStorageThresholdMaxBytes, defaultThresholdMaxBytes);
+        }
+
+        long minFreePercentInBytes = (partitionTotalBytes * minFreePercent) / 100;
+
+        return Math.min(minFreeBytes, minFreePercentInBytes);
+    }
 }
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 c6b8b5a..db9a469 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
@@ -178,7 +178,7 @@
                         mRecyclerView, mContextMenuManager, mUiDelegate, mUiConfig);
 
             case ItemViewType.PROMO:
-                return new SignInPromo.ViewHolder(mRecyclerView, mContextMenuManager, mUiConfig);
+                return mSigninPromo.createViewHolder(mRecyclerView, mContextMenuManager, mUiConfig);
 
             case ItemViewType.FOOTER:
                 return new Footer.ViewHolder(mRecyclerView, mUiDelegate.getNavigationDelegate());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SignInPromo.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SignInPromo.java
index 9126fe5..979a7c8b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SignInPromo.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SignInPromo.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.ntp.cards;
 
+import android.accounts.Account;
 import android.content.Context;
 import android.support.annotation.DrawableRes;
 import android.support.annotation.Nullable;
@@ -12,24 +13,34 @@
 import org.chromium.base.Callback;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.VisibleForTesting;
+import org.chromium.base.annotations.SuppressFBWarnings;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.ntp.ContextMenuManager;
 import org.chromium.chrome.browser.ntp.snippets.CategoryInt;
 import org.chromium.chrome.browser.ntp.snippets.CategoryStatus;
 import org.chromium.chrome.browser.ntp.snippets.SnippetsBridge;
 import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource;
 import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
+import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.signin.AccountSigninActivity;
+import org.chromium.chrome.browser.signin.ProfileDataCache;
 import org.chromium.chrome.browser.signin.SigninAccessPoint;
 import org.chromium.chrome.browser.signin.SigninManager;
 import org.chromium.chrome.browser.signin.SigninManager.SignInAllowedObserver;
 import org.chromium.chrome.browser.signin.SigninManager.SignInStateObserver;
+import org.chromium.chrome.browser.signin.SigninPromoController;
+import org.chromium.chrome.browser.signin.SigninPromoView;
 import org.chromium.chrome.browser.suggestions.DestructionObserver;
 import org.chromium.chrome.browser.suggestions.SuggestionsRecyclerView;
 import org.chromium.chrome.browser.suggestions.SuggestionsUiDelegate;
 import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.chrome.browser.widget.displaystyle.UiConfig;
+import org.chromium.components.signin.AccountManagerFacade;
+import org.chromium.components.signin.AccountsChangeObserver;
+
+import java.util.Collections;
 
 /**
  * Shows a card prompting the user to sign in. This item is also an {@link OptionalLeaf}, and sign
@@ -37,10 +48,14 @@
  */
 public class SignInPromo extends OptionalLeaf
         implements StatusCardViewHolder.DataSource, ImpressionTracker.Listener {
+    /**
+     * Whether the promo had been previously dismissed, before creating an instance of the
+     * {@link SignInPromo}.
+     */
+    private final boolean mWasDismissed;
 
     /**
-     * Whether the user has seen the promo and dismissed it at some point. When this is set,
-     * the promo will never be shown.
+     * Whether the promo has been dismissed by the user.
      */
     private boolean mDismissed;
 
@@ -57,24 +72,59 @@
 
     private final ImpressionTracker mImpressionTracker = new ImpressionTracker(null, this);
 
-    @Nullable
-    private final SigninObserver mSigninObserver;
+    private final @Nullable SigninObserver mSigninObserver;
+
+    /**
+     * Marks which are the parts of the code that switch between the generic and the personalized
+     * signin promos. When the personalized promos launch completely, the dead code related to the
+     * generic promos should be removed. It is also an indicator whether the Finch flag for the
+     * personalized signin promo is enabled.
+     */
+    private final boolean mArePersonalizedPromosEnabled;
+    private final @Nullable SigninPromoController mSigninPromoController;
+    private final @Nullable ProfileDataCache mProfileDataCache;
 
     public SignInPromo(SuggestionsUiDelegate uiDelegate) {
-        mDismissed = ChromePreferenceManager.getInstance().getNewTabPageSigninPromoDismissed();
+        mArePersonalizedPromosEnabled =
+                ChromeFeatureList.isEnabled(ChromeFeatureList.ANDROID_SIGNIN_PROMOS);
+
+        ChromePreferenceManager preferenceManager = ChromePreferenceManager.getInstance();
+        if (mArePersonalizedPromosEnabled) {
+            mWasDismissed = preferenceManager.getNewTabPagePersonalizedSigninPromoDismissed();
+        } else {
+            mWasDismissed = preferenceManager.getNewTabPageGenericSigninPromoDismissed();
+        }
 
         SuggestionsSource suggestionsSource = uiDelegate.getSuggestionsSource();
         SigninManager signinManager = SigninManager.get(ContextUtils.getApplicationContext());
-        if (mDismissed) {
-            mSigninObserver = null;
-        } else {
-            mSigninObserver = new SigninObserver(signinManager, suggestionsSource);
-            uiDelegate.addDestructionObserver(mSigninObserver);
-        }
 
         mCanSignIn = signinManager.isSignInAllowed() && !signinManager.isSignedInOnNative();
         mCanShowPersonalizedSuggestions = suggestionsSource.areRemoteSuggestionsEnabled();
+        mDismissed = mWasDismissed;
+
         updateVisibility();
+
+        if (mWasDismissed) {
+            mSigninObserver = null;
+            mProfileDataCache = null;
+            mSigninPromoController = null;
+            return;
+        }
+
+        if (mArePersonalizedPromosEnabled) {
+            Context context = ContextUtils.getApplicationContext();
+            int imageSize = context.getResources().getDimensionPixelSize(R.dimen.user_picture_size);
+            mProfileDataCache =
+                    new ProfileDataCache(context, Profile.getLastUsedProfile(), imageSize);
+            mSigninPromoController = new SigninPromoController(
+                    mProfileDataCache, SigninAccessPoint.NTP_CONTENT_SUGGESTIONS);
+        } else {
+            mProfileDataCache = null;
+            mSigninPromoController = null;
+        }
+
+        mSigninObserver = new SigninObserver(signinManager, suggestionsSource);
+        uiDelegate.addDestructionObserver(mSigninObserver);
     }
 
     @Override
@@ -92,10 +142,29 @@
         return mSigninObserver;
     }
 
+    /**
+     * @return a {@link NewTabPageViewHolder} which will contain the view for the signin promo.
+     */
+    public NewTabPageViewHolder createViewHolder(SuggestionsRecyclerView parent,
+            ContextMenuManager contextMenuManager, UiConfig config) {
+        assert !mWasDismissed;
+        if (mArePersonalizedPromosEnabled) {
+            return new PersonalizedPromoViewHolder(
+                    parent, contextMenuManager, config, mProfileDataCache, mSigninPromoController);
+        }
+        return new GenericPromoViewHolder(parent, contextMenuManager, config);
+    }
+
+    @SuppressFBWarnings("BC_UNCONFIRMED_CAST")
     @Override
     protected void onBindViewHolder(NewTabPageViewHolder holder) {
-        assert holder instanceof StatusCardViewHolder;
-        ((StatusCardViewHolder) holder).onBindViewHolder(this);
+        assert !mWasDismissed;
+        if (mArePersonalizedPromosEnabled) {
+            ((PersonalizedPromoViewHolder) holder).onBindViewHolder();
+        } else {
+            ((GenericPromoViewHolder) holder).onBindViewHolder(this);
+        }
+
         mImpressionTracker.reset(mImpressionTracker.wasTriggered() ? null : holder.itemView);
     }
 
@@ -129,7 +198,12 @@
 
     @Override
     public void onImpression() {
-        RecordUserAction.record("Signin_Impression_FromNTPContentSuggestions");
+        assert !mWasDismissed;
+        if (mArePersonalizedPromosEnabled) {
+            mSigninPromoController.recordSigninPromoImpression();
+        } else {
+            RecordUserAction.record("Signin_Impression_FromNTPContentSuggestions");
+        }
         mImpressionTracker.reset(null);
     }
 
@@ -145,18 +219,25 @@
     /** Hides the sign in promo and sets a preference to make sure it is not shown again. */
     @Override
     public void dismiss(Callback<String> itemRemovedCallback) {
-        assert mSigninObserver != null;
+        assert !mWasDismissed;
         mDismissed = true;
         updateVisibility();
 
-        ChromePreferenceManager.getInstance().setNewTabPageSigninPromoDismissed(true);
+        ChromePreferenceManager preferenceManager = ChromePreferenceManager.getInstance();
+        if (mArePersonalizedPromosEnabled) {
+            preferenceManager.setNewTabPagePersonalizedSigninPromoDismissed(true);
+        } else {
+            preferenceManager.setNewTabPageGenericSigninPromoDismissed(true);
+        }
+
         mSigninObserver.unregister();
         itemRemovedCallback.onResult(ContextUtils.getApplicationContext().getString(getHeader()));
     }
 
     @VisibleForTesting
     class SigninObserver extends SuggestionsSource.EmptyObserver
-            implements SignInStateObserver, SignInAllowedObserver, DestructionObserver {
+            implements SignInStateObserver, SignInAllowedObserver, DestructionObserver,
+                       ProfileDataCache.Observer, AccountsChangeObserver {
         private final SigninManager mSigninManager;
         private final SuggestionsSource mSuggestionsSource;
 
@@ -164,15 +245,24 @@
         private boolean mUnregistered;
 
         private SigninObserver(SigninManager signinManager, SuggestionsSource suggestionsSource) {
+            assert !mWasDismissed;
+
             mSigninManager = signinManager;
             mSigninManager.addSignInAllowedObserver(this);
             mSigninManager.addSignInStateObserver(this);
 
             mSuggestionsSource = suggestionsSource;
             mSuggestionsSource.addObserver(this);
+
+            if (mArePersonalizedPromosEnabled) {
+                mProfileDataCache.addObserver(this);
+                AccountManagerFacade.get().addObserver(this);
+            }
         }
 
         private void unregister() {
+            assert !mWasDismissed;
+
             if (mUnregistered) return;
             mUnregistered = true;
 
@@ -180,13 +270,22 @@
             mSigninManager.removeSignInStateObserver(this);
 
             mSuggestionsSource.removeObserver(this);
+
+            if (mArePersonalizedPromosEnabled) {
+                mProfileDataCache.removeObserver(this);
+                AccountManagerFacade.get().removeObserver(this);
+            }
         }
 
+        // DestructionObserver implementation.
+
         @Override
         public void onDestroy() {
             unregister();
         }
 
+        // SignInAllowedObserver implementation.
+
         @Override
         public void onSignInAllowedChanged() {
             // Listening to onSignInAllowedChanged is important for the FRE. Sign in is not allowed
@@ -196,6 +295,8 @@
             updateVisibility();
         }
 
+        // SignInStateObserver implementation.
+
         @Override
         public void onSignedIn() {
             mCanSignIn = false;
@@ -218,14 +319,72 @@
                     || mSuggestionsSource.areRemoteSuggestionsEnabled();
             updateVisibility();
         }
+
+        // AccountsChangeObserver implementation.
+
+        @Override
+        public void onAccountsChanged() {
+            notifyPersonalizedPromoIfVisible();
+        }
+
+        // ProfileDataCache.Observer implementation.
+
+        @Override
+        public void onProfileDataUpdated(String accountId) {
+            notifyPersonalizedPromoIfVisible();
+        }
+
+        private void notifyPersonalizedPromoIfVisible() {
+            if (isVisible()) notifyItemChanged(0, new UpdatePersonalizedSigninPromoCallback());
+        }
     }
 
     /**
-     * View Holder for {@link SignInPromo}.
+     * View Holder for {@link SignInPromo} if the personalized promo is to be shown.
      */
-    public static class ViewHolder extends StatusCardViewHolder {
-        public ViewHolder(SuggestionsRecyclerView parent, ContextMenuManager contextMenuManager,
-                UiConfig config) {
+    private static class PersonalizedPromoViewHolder extends CardViewHolder {
+        private final ProfileDataCache mProfileDataCache;
+        private final SigninPromoController mSigninPromoController;
+
+        public PersonalizedPromoViewHolder(SuggestionsRecyclerView parent,
+                ContextMenuManager contextMenuManager, UiConfig config,
+                ProfileDataCache profileDataCache, SigninPromoController signinPromoController) {
+            super(R.layout.personalized_signin_promo_view_ntp_content_suggestions, parent, config,
+                    contextMenuManager);
+            getParams().topMargin = parent.getResources().getDimensionPixelSize(
+                    R.dimen.ntp_sign_in_promo_margin_top);
+
+            mProfileDataCache = profileDataCache;
+            mSigninPromoController = signinPromoController;
+        }
+
+        @Override
+        protected void onBindViewHolder() {
+            super.onBindViewHolder();
+            updatePersonalizedSigninPromo();
+        }
+
+        private void updatePersonalizedSigninPromo() {
+            Account[] accounts = AccountManagerFacade.get().tryGetGoogleAccounts();
+            String defaultAccountName = accounts.length == 0 ? null : accounts[0].name;
+
+            if (defaultAccountName != null) {
+                mProfileDataCache.update(Collections.singletonList(defaultAccountName));
+            }
+
+            mSigninPromoController.setAccountName(defaultAccountName);
+
+            SigninPromoView view = (SigninPromoView) itemView;
+            mSigninPromoController.setupSigninPromoView(view.getContext(), view, null);
+        }
+    }
+
+    /**
+     * View Holder for {@link SignInPromo} if the generic promo is to be shown.
+     */
+    public static class GenericPromoViewHolder extends StatusCardViewHolder {
+        public GenericPromoViewHolder(SuggestionsRecyclerView parent,
+                ContextMenuManager contextMenuManager, UiConfig config) {
             super(parent, contextMenuManager, config);
             getParams().topMargin = parent.getResources().getDimensionPixelSize(
                     R.dimen.ntp_sign_in_promo_margin_top);
@@ -239,4 +398,16 @@
             return R.drawable.ntp_signin_promo_card_single;
         }
     }
+
+    /**
+     * Callback to update the personalized signin promo.
+     */
+    private static class UpdatePersonalizedSigninPromoCallback
+            extends NewTabPageViewHolder.PartialBindCallback {
+        @SuppressFBWarnings("BC_UNCONFIRMED_CAST")
+        @Override
+        public void onResult(NewTabPageViewHolder result) {
+            ((PersonalizedPromoViewHolder) result).updatePersonalizedSigninPromo();
+        }
+    }
 }
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 19984d9..d7a3014 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
@@ -2242,7 +2242,6 @@
 
             setUrlToPageUrl();
             RecordUserAction.record("MobileOmniboxUse");
-            RecordUserAction.record("MobileTabClobbered");
         } else {
             setUrlToPageUrl();
         }
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
index 0d56ecfc3..41d7fe7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/SpannableAutocompleteEditTextModel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/SpannableAutocompleteEditTextModel.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.omnibox;
 
+import android.os.Bundle;
 import android.text.Editable;
 import android.text.Selection;
 import android.text.SpannableString;
@@ -12,10 +13,13 @@
 import android.view.KeyEvent;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.inputmethod.BaseInputConnection;
+import android.view.inputmethod.CompletionInfo;
+import android.view.inputmethod.CorrectionInfo;
 import android.view.inputmethod.ExtractedText;
 import android.view.inputmethod.ExtractedTextRequest;
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputConnectionWrapper;
+import android.view.inputmethod.InputContentInfo;
 
 import org.chromium.base.Log;
 import org.chromium.base.VisibleForTesting;
@@ -206,8 +210,8 @@
         clearAutocompleteText();
         // Take effect and notify if not already in a batch edit.
         if (mInputConnection != null) {
-            mInputConnection.beginBatchEdit();
-            mInputConnection.endBatchEdit();
+            mInputConnection.onBeginImeCommand();
+            mInputConnection.onEndImeCommand();
         } else {
             mSpanCursorController.removeSpan();
             notifyAutocompleteTextStateChanged();
@@ -220,13 +224,13 @@
         if (mInputConnection == null) {
             return mDelegate.super_dispatchKeyEvent(event);
         }
-        mInputConnection.beginBatchEdit();
+        mInputConnection.onBeginImeCommand();
         if (event.getKeyCode() == KeyEvent.KEYCODE_ENTER
                 && event.getAction() == KeyEvent.ACTION_DOWN) {
             mInputConnection.commitAutocomplete();
         }
         boolean retVal = mDelegate.super_dispatchKeyEvent(event);
-        mInputConnection.endBatchEdit();
+        mInputConnection.onEndImeCommand();
         return retVal;
     }
 
@@ -310,8 +314,8 @@
         // 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();
+            mInputConnection.onBeginImeCommand();
+            mInputConnection.onEndImeCommand();
         }
     }
 
@@ -478,7 +482,12 @@
             return retVal;
         }
 
-        private boolean onBeginImeCommand() {
+        /**
+         * Always call this at the beginning of any IME command. Compare this with beginBatchEdit()
+         * which is by itself an IME command.
+         * @return Whether the call was successful.
+         */
+        public boolean onBeginImeCommand() {
             if (DEBUG) Log.i(TAG, "onBeginImeCommand: " + mBatchEditNestCount);
             boolean retVal = incrementBatchEditCount();
             if (mBatchEditNestCount == 1) {
@@ -531,7 +540,12 @@
             return retVal;
         }
 
-        private boolean onEndImeCommand() {
+        /**
+         * Always call this at the end of an IME command. Compare this with endBatchEdit()
+         * which is by itself an IME command.
+         * @return Whether the call was successful.
+         */
+        public boolean onEndImeCommand() {
             if (DEBUG) Log.i(TAG, "onEndImeCommand: " + (mBatchEditNestCount - 1));
             String diff = mCurrentState.getBackwardDeletedTextFrom(mPreBatchEditState);
             if (diff != null) {
@@ -670,5 +684,68 @@
             onEndImeCommand();
             return retVal;
         }
+
+        @Override
+        public boolean commitCompletion(CompletionInfo text) {
+            if (DEBUG) Log.i(TAG, "commitCompletion");
+            onBeginImeCommand();
+            boolean retVal = super.commitCompletion(text);
+            onEndImeCommand();
+            return retVal;
+        }
+
+        @Override
+        public boolean commitContent(InputContentInfo inputContentInfo, int flags, Bundle opts) {
+            if (DEBUG) Log.i(TAG, "commitContent");
+            onBeginImeCommand();
+            boolean retVal = super.commitContent(inputContentInfo, flags, opts);
+            onEndImeCommand();
+            return retVal;
+        }
+
+        @Override
+        public boolean commitCorrection(CorrectionInfo correctionInfo) {
+            if (DEBUG) Log.i(TAG, "commitCorrection");
+            onBeginImeCommand();
+            boolean retVal = super.commitCorrection(correctionInfo);
+            onEndImeCommand();
+            return retVal;
+        }
+
+        @Override
+        public boolean deleteSurroundingTextInCodePoints(int beforeLength, int afterLength) {
+            if (DEBUG) Log.i(TAG, "deleteSurroundingTextInCodePoints");
+            onBeginImeCommand();
+            boolean retVal = super.deleteSurroundingTextInCodePoints(beforeLength, afterLength);
+            onEndImeCommand();
+            return retVal;
+        }
+
+        @Override
+        public int getCursorCapsMode(int reqModes) {
+            if (DEBUG) Log.i(TAG, "getCursorCapsMode");
+            onBeginImeCommand();
+            int retVal = super.getCursorCapsMode(reqModes);
+            onEndImeCommand();
+            return retVal;
+        }
+
+        @Override
+        public boolean requestCursorUpdates(int cursorUpdateMode) {
+            if (DEBUG) Log.i(TAG, "requestCursorUpdates");
+            onBeginImeCommand();
+            boolean retVal = super.requestCursorUpdates(cursorUpdateMode);
+            onEndImeCommand();
+            return retVal;
+        }
+
+        @Override
+        public boolean clearMetaKeyStates(int states) {
+            if (DEBUG) Log.i(TAG, "clearMetaKeyStates");
+            onBeginImeCommand();
+            boolean retVal = super.clearMetaKeyStates(states);
+            onEndImeCommand();
+            return retVal;
+        }
     }
 }
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 9833a25..134be19 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
@@ -49,7 +49,11 @@
 
     private static final String CONTENT_SUGGESTIONS_SHOWN_KEY = "content_suggestions_shown";
 
-    private static final String NTP_SIGNIN_PROMO_DISMISSED = "ntp.signin_promo_dismissed";
+    // TODO(crbug.com/757892): Remove this preference key once the personalized signin promos
+    // launch completely.
+    private static final String NTP_GENERIC_SIGNIN_PROMO_DISMISSED = "ntp.signin_promo_dismissed";
+    private static final String NTP_PERSONALIZED_SIGNIN_PROMO_DISMISSED =
+            "ntp.personalized_signin_promo_dismissed";
     private static final String NTP_ANIMATION_RUN_COUNT = "ntp_recycler_view_animation_run_count";
 
     private static final String SUCCESS_UPLOAD_SUFFIX = "_crash_success_upload";
@@ -351,14 +355,24 @@
         writeBoolean(CHROME_DEFAULT_BROWSER, isDefault);
     }
 
-    /** Checks if the user dismissed the sign in promo from the new tab page. */
-    public boolean getNewTabPageSigninPromoDismissed() {
-        return mSharedPreferences.getBoolean(NTP_SIGNIN_PROMO_DISMISSED, false);
+    /** Checks if the user dismissed the generic sign in promo from the new tab page. */
+    public boolean getNewTabPageGenericSigninPromoDismissed() {
+        return mSharedPreferences.getBoolean(NTP_GENERIC_SIGNIN_PROMO_DISMISSED, false);
     }
 
-    /** Set whether the user dismissed the sign in promo from the new tab page. */
-    public void setNewTabPageSigninPromoDismissed(boolean isPromoDismissed) {
-        writeBoolean(NTP_SIGNIN_PROMO_DISMISSED, isPromoDismissed);
+    /** Set whether the user dismissed the generic sign in promo from the new tab page. */
+    public void setNewTabPageGenericSigninPromoDismissed(boolean isPromoDismissed) {
+        writeBoolean(NTP_GENERIC_SIGNIN_PROMO_DISMISSED, isPromoDismissed);
+    }
+
+    /** Checks if the user dismissed the personalized sign in promo from the new tab page. */
+    public boolean getNewTabPagePersonalizedSigninPromoDismissed() {
+        return mSharedPreferences.getBoolean(NTP_PERSONALIZED_SIGNIN_PROMO_DISMISSED, false);
+    }
+
+    /** Set whether the user dismissed the personalized sign in promo from the new tab page. */
+    public void setNewTabPagePersonalizedSigninPromoDismissed(boolean isPromoDismissed) {
+        writeBoolean(NTP_PERSONALIZED_SIGNIN_PROMO_DISMISSED, isPromoDismissed);
     }
 
     /** Gets the number of times the New Tab Page first card animation has been run. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninPromoController.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninPromoController.java
index fe22060..e61bd3c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninPromoController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninPromoController.java
@@ -46,8 +46,8 @@
     private final @AccountSigninActivity.AccessPoint int mAccessPoint;
     private final @Nullable String mImpressionCountName;
     private final String mImpressionUserActionName;
-    private final @Nullable String mImpressionWithAccountUserActionName;
-    private final @Nullable String mImpressionWithNoAccountUserActionName;
+    private final String mImpressionWithAccountUserActionName;
+    private final String mImpressionWithNoAccountUserActionName;
     private final @StringRes int mDescriptionStringId;
 
     /**
@@ -104,10 +104,10 @@
                 // There is no impression limit for NTP content suggestions.
                 mImpressionCountName = null;
                 mImpressionUserActionName = "Signin_Impression_FromNTPContentSuggestions";
-                // TODO(iuliah): create Signin_ImpressionWithAccount_FromNTPContentSuggestions.
-                mImpressionWithAccountUserActionName = null;
-                // TODO(iuliah): create Signin_ImpressionWithNoAccount_FromNTPContentSuggestions.
-                mImpressionWithNoAccountUserActionName = null;
+                mImpressionWithAccountUserActionName =
+                        "Signin_ImpressionWithAccount_FromNTPContentSuggestions";
+                mImpressionWithNoAccountUserActionName =
+                        "Signin_ImpressionWithNoAccount_FromNTPContentSuggestions";
                 mDescriptionStringId = R.string.signin_promo_description_ntp_content_suggestions;
                 break;
             case SigninAccessPoint.RECENT_TABS:
@@ -140,9 +140,9 @@
     public void recordSigninPromoImpression() {
         RecordUserAction.record(mImpressionUserActionName);
         if (mAccountName == null) {
-            recordSigninImpressionWithNoAccountUserAction();
+            RecordUserAction.record(mImpressionWithNoAccountUserActionName);
         } else {
-            recordSigninImpressionWithAccountUserAction();
+            RecordUserAction.record(mImpressionWithAccountUserActionName);
         }
 
         // If mImpressionCountName is not null then we should record impressions.
@@ -192,18 +192,6 @@
         mAccountName = accountName;
     }
 
-    private void recordSigninImpressionWithAccountUserAction() {
-        if (mImpressionWithAccountUserActionName != null) {
-            RecordUserAction.record(mImpressionWithAccountUserActionName);
-        }
-    }
-
-    private void recordSigninImpressionWithNoAccountUserAction() {
-        if (mImpressionWithNoAccountUserActionName != null) {
-            RecordUserAction.record(mImpressionWithNoAccountUserActionName);
-        }
-    }
-
     private void setupColdState(final Context context, SigninPromoView view) {
         view.getImage().setImageResource(R.drawable.chrome_sync_logo);
         setImageSize(context, view, R.dimen.signin_promo_cold_state_image_size);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarTablet.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarTablet.java
index 4adb903..2de979d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarTablet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarTablet.java
@@ -301,11 +301,9 @@
         } else if (mBackButton == v) {
             if (!back()) return;
             RecordUserAction.record("MobileToolbarBack");
-            RecordUserAction.record("MobileTabClobbered");
         } else if (mForwardButton == v) {
             forward();
             RecordUserAction.record("MobileToolbarForward");
-            RecordUserAction.record("MobileTabClobbered");
         } else if (mReloadButton == v) {
             stopOrReloadCurrentTab();
         } else if (mBookmarkButton == v) {
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 85f09df..e2e3e6ad 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -325,6 +325,7 @@
   "java/src/org/chromium/chrome/browser/download/ChromeDownloadDelegate.java",
   "java/src/org/chromium/chrome/browser/download/DownloadActivity.java",
   "java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java",
+  "java/src/org/chromium/chrome/browser/download/DownloadBroadcastReceiver.java",
   "java/src/org/chromium/chrome/browser/download/DownloadController.java",
   "java/src/org/chromium/chrome/browser/download/DownloadForegroundService.java",
   "java/src/org/chromium/chrome/browser/download/DownloadForegroundServiceManager.java",
@@ -334,9 +335,11 @@
   "java/src/org/chromium/chrome/browser/download/DownloadManagerService.java",
   "java/src/org/chromium/chrome/browser/download/DownloadNotificationFactory.java",
   "java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java",
+  "java/src/org/chromium/chrome/browser/download/DownloadNotificationService2.java",
   "java/src/org/chromium/chrome/browser/download/DownloadNotifier.java",
   "java/src/org/chromium/chrome/browser/download/DownloadPage.java",
   "java/src/org/chromium/chrome/browser/download/DownloadResumptionScheduler.java",
+  "java/src/org/chromium/chrome/browser/download/DownloadResumptionScheduler2.java",
   "java/src/org/chromium/chrome/browser/download/DownloadServiceDelegate.java",
   "java/src/org/chromium/chrome/browser/download/DownloadSharedPreferenceEntry.java",
   "java/src/org/chromium/chrome/browser/download/DownloadSharedPreferenceHelper.java",
@@ -347,6 +350,7 @@
   "java/src/org/chromium/chrome/browser/download/DownloadUtils.java",
   "java/src/org/chromium/chrome/browser/download/OMADownloadHandler.java",
   "java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier.java",
+  "java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier2.java",
   "java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorFactory.java",
   "java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorNotificationBridgeUi.java",
   "java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorNotificationBridgeUiFactory.java",
@@ -1439,11 +1443,13 @@
   "javatests/src/org/chromium/chrome/browser/download/DownloadActivityTest.java",
   "javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java",
   "javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java",
+  "javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest2.java",
   "javatests/src/org/chromium/chrome/browser/download/DownloadForegroundServiceManagerTest.java",
   "javatests/src/org/chromium/chrome/browser/download/DownloadTest.java",
   "javatests/src/org/chromium/chrome/browser/download/DownloadTestRule.java",
   "javatests/src/org/chromium/chrome/browser/download/DownloadUtilsTest.java",
   "javatests/src/org/chromium/chrome/browser/download/MockDownloadNotificationService.java",
+  "javatests/src/org/chromium/chrome/browser/download/MockDownloadNotificationService2.java",
   "javatests/src/org/chromium/chrome/browser/download/OMADownloadHandlerTest.java",
   "javatests/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapterTest.java",
   "javatests/src/org/chromium/chrome/browser/download/ui/StubbedProvider.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java
index 6ec273c..da2d3a2 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java
@@ -4,202 +4,548 @@
 
 package org.chromium.chrome.browser.download;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
+import android.content.Context;
+import android.content.Intent;
 import android.content.SharedPreferences;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
 import android.support.test.filters.SmallTest;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+import android.test.ServiceTestCase;
 
 import org.chromium.base.ContextUtils;
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.util.AdvancedMockContext;
 import org.chromium.base.test.util.Feature;
-import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.base.test.util.RetryOnFailure;
 import org.chromium.components.offline_items_collection.ContentId;
 import org.chromium.components.offline_items_collection.LegacyHelpers;
 import org.chromium.components.offline_items_collection.OfflineItem.Progress;
 import org.chromium.components.offline_items_collection.OfflineItemProgressUnit;
 
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
 import java.util.UUID;
 
 /**
  * Tests of {@link DownloadNotificationService}.
  */
-@RunWith(ChromeJUnit4ClassRunner.class)
-public class DownloadNotificationServiceTest {
-    private static final ContentId ID1 =
-            LegacyHelpers.buildLegacyContentId(false, UUID.randomUUID().toString());
-    private static final ContentId ID2 =
-            LegacyHelpers.buildLegacyContentId(false, UUID.randomUUID().toString());
-    private static final ContentId ID3 =
-            LegacyHelpers.buildLegacyContentId(false, UUID.randomUUID().toString());
+public class DownloadNotificationServiceTest
+        extends ServiceTestCase<MockDownloadNotificationService> {
+    private static class MockDownloadManagerService extends DownloadManagerService {
+        final List<DownloadItem> mDownloads = new ArrayList<DownloadItem>();
 
-    private MockDownloadNotificationService mDownloadNotificationService;
-    private DownloadForegroundServiceManagerTest
-            .MockDownloadForegroundServiceManager mDownloadForegroundServiceManager;
-    private DownloadSharedPreferenceHelper mDownloadSharedPreferenceHelper;
+        public MockDownloadManagerService(Context context) {
+            super(context, null, getTestHandler(), 1000);
+        }
 
-    private static DownloadSharedPreferenceEntry buildEntryStringWithGuid(ContentId contentId,
+        @Override
+        protected void init() {}
+
+        @Override
+        public void resumeDownload(ContentId id, DownloadItem item, boolean hasUserGesture) {
+            mDownloads.add(item);
+        }
+    }
+
+    private static class MockDownloadResumptionScheduler extends DownloadResumptionScheduler {
+        boolean mScheduled;
+
+        public MockDownloadResumptionScheduler(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void schedule(boolean allowMeteredConnection) {
+            mScheduled = true;
+        }
+
+        @Override
+        public void cancelTask() {
+            mScheduled = false;
+        }
+    }
+
+    private static String buildEntryStringWithGuid(String guid, int notificationId, String fileName,
+            boolean metered, boolean autoResume, boolean offTheRecord) {
+        return new DownloadSharedPreferenceEntry(LegacyHelpers.buildLegacyContentId(false, guid),
+                notificationId, offTheRecord, metered, fileName, autoResume, false)
+                .getSharedPreferenceString();
+    }
+
+    private static String buildEntryStringWithGuid(
+            String guid, int notificationId, String fileName, boolean metered, boolean autoResume) {
+        return buildEntryStringWithGuid(guid, notificationId, fileName, metered, autoResume, false);
+    }
+
+    private static String buildEntryString(
             int notificationId, String fileName, boolean metered, boolean autoResume) {
-        return new DownloadSharedPreferenceEntry(
-                contentId, notificationId, false, metered, fileName, autoResume, false);
+        return buildEntryStringWithGuid(
+                UUID.randomUUID().toString(), notificationId, fileName, metered, autoResume);
     }
 
-    @Before
-    public void setUp() {
-        mDownloadNotificationService = new MockDownloadNotificationService();
-        mDownloadForegroundServiceManager =
-                new DownloadForegroundServiceManagerTest.MockDownloadForegroundServiceManager();
-        mDownloadNotificationService.setDownloadForegroundServiceManager(
-                mDownloadForegroundServiceManager);
-        mDownloadSharedPreferenceHelper = DownloadSharedPreferenceHelper.getInstance();
+    public DownloadNotificationServiceTest() {
+        super(MockDownloadNotificationService.class);
     }
 
-    @After
-    public void tearDown() {
+    @Override
+    protected void setupService() {
+        super.setupService();
+    }
+
+    @Override
+    protected void shutdownService() {
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                DownloadNotificationServiceTest.super.shutdownService();
+            }
+        });
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
         SharedPreferences sharedPrefs = ContextUtils.getAppSharedPreferences();
         SharedPreferences.Editor editor = sharedPrefs.edit();
         editor.remove(DownloadSharedPreferenceHelper.KEY_PENDING_DOWNLOAD_NOTIFICATIONS);
         editor.apply();
+        super.tearDown();
     }
 
-    @Test
+    private void startNotificationService() {
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                Intent intent = new Intent(getService(), MockDownloadNotificationService.class);
+                startService(intent);
+            }
+        });
+    }
+
+    private DownloadNotificationService bindNotificationService() {
+        Intent intent = new Intent(getService(), MockDownloadNotificationService.class);
+        IBinder service = bindService(intent);
+        return ((DownloadNotificationService.LocalBinder) service).getService();
+    }
+
+    private static Handler getTestHandler() {
+        HandlerThread handlerThread = new HandlerThread("handlerThread");
+        handlerThread.start();
+        return new Handler(handlerThread.getLooper());
+    }
+
+    private void resumeAllDownloads(final DownloadNotificationService service) throws Exception {
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                service.resumeAllPendingDownloads();
+            }
+        });
+    }
+
+    /**
+     * Tests that creating the service without launching chrome will do nothing if there is no
+     * ongoing download.
+     */
     @SmallTest
     @Feature({"Download"})
-    public void testBasicDownloadFlow() {
-        // Download is in-progress.
-        mDownloadNotificationService.notifyDownloadProgress(ID1, "test",
+    public void testPausingWithoutOngoingDownloads() {
+        setupService();
+        startNotificationService();
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                getService().updateNotificationsForShutdown();
+            }
+        });
+        assertTrue(getService().isPaused());
+        assertTrue(getService().getNotificationIds().isEmpty());
+    }
+
+    /**
+     * Tests that download resumption task is scheduled when notification service is started
+     * without any download action.
+     */
+    @SmallTest
+    @Feature({"Download"})
+    public void testResumptionScheduledWithoutDownloadOperationIntent() throws Exception {
+        MockDownloadResumptionScheduler scheduler =
+                new MockDownloadResumptionScheduler(getSystemContext().getApplicationContext());
+        DownloadResumptionScheduler.setDownloadResumptionScheduler(scheduler);
+        setupService();
+        Set<String> notifications = new HashSet<>();
+        notifications.add(buildEntryString(1, "test1", true, true));
+        SharedPreferences sharedPrefs = ContextUtils.getAppSharedPreferences();
+        SharedPreferences.Editor editor = sharedPrefs.edit();
+        editor.putStringSet(
+                DownloadSharedPreferenceHelper.KEY_PENDING_DOWNLOAD_NOTIFICATIONS, notifications);
+        editor.apply();
+        startNotificationService();
+        shutdownService();
+        assertTrue(scheduler.mScheduled);
+    }
+
+    /**
+     * Tests that download resumption task is not scheduled when notification service is started
+     * with a download action.
+     */
+    @SmallTest
+    @Feature({"Download"})
+    public void testResumptionNotScheduledWithDownloadOperationIntent() {
+        MockDownloadResumptionScheduler scheduler =
+                new MockDownloadResumptionScheduler(getSystemContext().getApplicationContext());
+        DownloadResumptionScheduler.setDownloadResumptionScheduler(scheduler);
+        setupService();
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                Intent intent = new Intent(getService(), MockDownloadNotificationService.class);
+                intent.setAction(DownloadNotificationService.ACTION_DOWNLOAD_RESUME_ALL);
+                startService(intent);
+            }
+        });
+        assertFalse(scheduler.mScheduled);
+    }
+
+    /**
+     * Tests that download resumption task is not scheduled when there is no auto resumable
+     * download in SharedPreferences.
+     */
+    @SmallTest
+    @Feature({"Download"})
+    public void testResumptionNotScheduledWithoutAutoResumableDownload() throws Exception {
+        MockDownloadResumptionScheduler scheduler =
+                new MockDownloadResumptionScheduler(getSystemContext().getApplicationContext());
+        DownloadResumptionScheduler.setDownloadResumptionScheduler(scheduler);
+        setupService();
+        Set<String> notifications = new HashSet<>();
+        notifications.add(buildEntryString(1, "test1", true, false));
+        SharedPreferences sharedPrefs = ContextUtils.getAppSharedPreferences();
+        SharedPreferences.Editor editor = sharedPrefs.edit();
+        editor.putStringSet(
+                DownloadSharedPreferenceHelper.KEY_PENDING_DOWNLOAD_NOTIFICATIONS, notifications);
+        editor.apply();
+        startNotificationService();
+        assertFalse(scheduler.mScheduled);
+    }
+
+    /**
+     * Tests that creating the service without launching chrome will pause all ongoing downloads.
+     */
+    @SmallTest
+    @Feature({"Download"})
+    public void testPausingWithOngoingDownloads() {
+        setupService();
+        Context mockContext = new AdvancedMockContext(getSystemContext());
+        getService().setContext(mockContext);
+        Set<String> notifications = new HashSet<>();
+        notifications.add(buildEntryString(1, "test1", true, true));
+        notifications.add(buildEntryString(2, "test2", true, true));
+        SharedPreferences sharedPrefs = ContextUtils.getAppSharedPreferences();
+        SharedPreferences.Editor editor = sharedPrefs.edit();
+        editor.putStringSet(
+                DownloadSharedPreferenceHelper.KEY_PENDING_DOWNLOAD_NOTIFICATIONS, notifications);
+        editor.apply();
+        startNotificationService();
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                getService().updateNotificationsForShutdown();
+            }
+        });
+        assertTrue(getService().isPaused());
+        assertEquals(2, getService().getNotificationIds().size());
+        assertTrue(getService().getNotificationIds().contains(1));
+        assertTrue(getService().getNotificationIds().contains(2));
+        assertTrue(sharedPrefs.contains(
+                DownloadSharedPreferenceHelper.KEY_PENDING_DOWNLOAD_NOTIFICATIONS));
+    }
+
+    /**
+     * Tests adding and cancelling notifications.
+     */
+    @SmallTest
+    @Feature({"Download"})
+    public void testAddingAndCancelingNotifications() {
+        setupService();
+        Context mockContext = new AdvancedMockContext(getSystemContext());
+        getService().setContext(mockContext);
+        Set<String> notifications = new HashSet<>();
+        String guid1 = UUID.randomUUID().toString();
+        String guid2 = UUID.randomUUID().toString();
+        notifications.add(buildEntryStringWithGuid(guid1, 3, "success", true, true));
+        notifications.add(buildEntryStringWithGuid(guid2, 4, "failed", true, true));
+        SharedPreferences sharedPrefs = ContextUtils.getAppSharedPreferences();
+        SharedPreferences.Editor editor = sharedPrefs.edit();
+        editor.putStringSet(
+                DownloadSharedPreferenceHelper.KEY_PENDING_DOWNLOAD_NOTIFICATIONS, notifications);
+        editor.apply();
+        startNotificationService();
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                getService().updateNotificationsForShutdown();
+            }
+        });
+        assertEquals(2, getService().getNotificationIds().size());
+        assertTrue(getService().getNotificationIds().contains(3));
+        assertTrue(getService().getNotificationIds().contains(4));
+
+        DownloadNotificationService service = bindNotificationService();
+        ContentId id3 = LegacyHelpers.buildLegacyContentId(false, UUID.randomUUID().toString());
+        service.notifyDownloadProgress(id3, "test",
                 new Progress(1, 100L, OfflineItemProgressUnit.PERCENTAGE), 100L, 1L, 1L, true, true,
                 false, null);
-        mDownloadForegroundServiceManager.onServiceConnected();
+        assertEquals(3, getService().getNotificationIds().size());
+        int lastNotificationId = getService().getLastAddedNotificationId();
+        Set<String> entries = DownloadManagerService.getStoredDownloadInfo(
+                sharedPrefs, DownloadSharedPreferenceHelper.KEY_PENDING_DOWNLOAD_NOTIFICATIONS);
+        assertEquals(3, entries.size());
 
-        assertEquals(1, mDownloadNotificationService.getNotificationIds().size());
-        int notificationId1 = mDownloadNotificationService.getLastNotificationId();
-        assertTrue(mDownloadForegroundServiceManager.mDownloadUpdateQueue.containsKey(
-                notificationId1));
-        assertTrue(mDownloadNotificationService.mDownloadsInProgress.contains(ID1));
+        ContentId id1 = LegacyHelpers.buildLegacyContentId(false, guid1);
+        service.notifyDownloadSuccessful(
+                id1, "/path/to/success", "success", 100L, false, false, true, null, null, null);
+        entries = DownloadManagerService.getStoredDownloadInfo(
+                sharedPrefs, DownloadSharedPreferenceHelper.KEY_PENDING_DOWNLOAD_NOTIFICATIONS);
+        assertEquals(2, entries.size());
 
-        // Download is paused.
-        mDownloadNotificationService.notifyDownloadPaused(ID1, "test", true /* isResumable*/,
-                false /* isAutoResumable */, true, false, null, false);
+        ContentId id2 = LegacyHelpers.buildLegacyContentId(false, guid2);
+        service.notifyDownloadFailed(id2, "failed", null);
+        entries = DownloadManagerService.getStoredDownloadInfo(
+                sharedPrefs, DownloadSharedPreferenceHelper.KEY_PENDING_DOWNLOAD_NOTIFICATIONS);
+        assertEquals(1, entries.size());
 
-        assertEquals(1, mDownloadNotificationService.getNotificationIds().size());
-        assertFalse(mDownloadForegroundServiceManager.mDownloadUpdateQueue.containsKey(
-                notificationId1));
-        assertFalse(mDownloadNotificationService.mDownloadsInProgress.contains(ID1));
+        service.notifyDownloadCanceled(id3);
+        assertEquals(2, getService().getNotificationIds().size());
+        assertFalse(getService().getNotificationIds().contains(lastNotificationId));
 
-        // Download is again in-progress.
-        mDownloadNotificationService.notifyDownloadProgress(ID1, "test",
-                new Progress(20, 100L, OfflineItemProgressUnit.PERCENTAGE), 100L, 1L, 1L, true,
-                true, false, null);
-        mDownloadForegroundServiceManager.onServiceConnected();
-
-        assertEquals(1, mDownloadNotificationService.getNotificationIds().size());
-        assertTrue(mDownloadForegroundServiceManager.mDownloadUpdateQueue.containsKey(
-                notificationId1));
-        assertTrue(mDownloadNotificationService.mDownloadsInProgress.contains(ID1));
-
-        // Download is successful.
-        mDownloadNotificationService.notifyDownloadSuccessful(
-                ID1, "", "test", 1L, true, true, true, null, "", "");
-        assertEquals(1, mDownloadNotificationService.getNotificationIds().size());
-        assertFalse(mDownloadForegroundServiceManager.mDownloadUpdateQueue.containsKey(
-                notificationId1));
-        assertFalse(mDownloadNotificationService.mDownloadsInProgress.contains(ID1));
+        ContentId id4 = LegacyHelpers.buildLegacyContentId(false, UUID.randomUUID().toString());
+        service.notifyDownloadSuccessful(
+                id4, "/path/to/success", "success", 100L, false, false, true, null, null, null);
+        assertEquals(3, getService().getNotificationIds().size());
+        int nextNotificationId = getService().getLastAddedNotificationId();
+        service.cancelNotification(nextNotificationId, id4);
+        assertEquals(2, getService().getNotificationIds().size());
+        assertFalse(getService().getNotificationIds().contains(nextNotificationId));
     }
 
-    @Test
+    /**
+     * Tests that notification is updated if download success comes without any prior progress.
+     */
     @SmallTest
     @Feature({"Download"})
-    public void testDownloadPendingAndCancelled() {
-        // Download is in-progress.
-        mDownloadNotificationService.notifyDownloadProgress(ID1, "test",
-                new Progress(1, 100L, OfflineItemProgressUnit.PERCENTAGE), 100L, 1L, 1L, true, true,
-                false, null);
-        mDownloadForegroundServiceManager.onServiceConnected();
-
-        assertEquals(1, mDownloadNotificationService.getNotificationIds().size());
-        int notificationId1 = mDownloadNotificationService.getLastNotificationId();
-        assertTrue(mDownloadForegroundServiceManager.mDownloadUpdateQueue.containsKey(
-                notificationId1));
-        assertTrue(mDownloadNotificationService.mDownloadsInProgress.contains(ID1));
-
-        // Download is interrupted and now is pending.
-        mDownloadNotificationService.notifyDownloadPaused(ID1, "test", true /* isResumable */,
-                true /* isAutoResumable */, true, false, null, false);
-        assertEquals(1, mDownloadNotificationService.getNotificationIds().size());
-        assertTrue(mDownloadForegroundServiceManager.mDownloadUpdateQueue.containsKey(
-                notificationId1));
-        assertFalse(mDownloadNotificationService.mDownloadsInProgress.contains(ID1));
-
-        // Download is cancelled.
-        mDownloadNotificationService.notifyDownloadCanceled(ID1, false);
-
-        assertEquals(0, mDownloadNotificationService.getNotificationIds().size());
-        assertFalse(mDownloadForegroundServiceManager.mDownloadUpdateQueue.containsKey(
-                notificationId1));
-        assertFalse(mDownloadNotificationService.mDownloadsInProgress.contains(ID1));
+    @RetryOnFailure
+    public void testDownloadSuccessNotification() {
+        setupService();
+        startNotificationService();
+        DownloadNotificationService service = bindNotificationService();
+        ContentId id = LegacyHelpers.buildLegacyContentId(false, UUID.randomUUID().toString());
+        service.notifyDownloadSuccessful(
+                id, "/path/to/test", "test", 100L, false, false, true, null, null, null);
+        assertEquals(1, getService().getNotificationIds().size());
     }
 
-    @Test
+    /**
+     * Tests resume all pending downloads. Only auto resumable downloads can resume.
+     */
     @SmallTest
     @Feature({"Download"})
-    public void testDownloadInterruptedAndFailed() {
-        // Download is in-progress.
-        mDownloadNotificationService.notifyDownloadProgress(ID1, "test",
-                new Progress(1, 100L, OfflineItemProgressUnit.PERCENTAGE), 100L, 1L, 1L, true, true,
-                false, null);
-        mDownloadForegroundServiceManager.onServiceConnected();
+    @RetryOnFailure
+    public void testResumeAllPendingDownloads() throws Exception {
+        setupService();
+        Context mockContext = new AdvancedMockContext(getSystemContext());
+        getService().setContext(mockContext);
+        Set<String> notifications = new HashSet<>();
+        String guid1 = UUID.randomUUID().toString();
+        String guid2 = UUID.randomUUID().toString();
+        String guid3 = UUID.randomUUID().toString();
 
-        assertEquals(1, mDownloadNotificationService.getNotificationIds().size());
-        int notificationId1 = mDownloadNotificationService.getLastNotificationId();
-        assertTrue(mDownloadForegroundServiceManager.mDownloadUpdateQueue.containsKey(
-                notificationId1));
-        assertTrue(mDownloadNotificationService.mDownloadsInProgress.contains(ID1));
+        notifications.add(buildEntryStringWithGuid(guid1, 3, "success", false, true));
+        notifications.add(buildEntryStringWithGuid(guid2, 4, "failed", true, true));
+        notifications.add(buildEntryStringWithGuid(guid3, 5, "nonresumable", true, false));
 
-        // Download is interrupted but because it is not resumable, fails.
-        mDownloadNotificationService.notifyDownloadPaused(ID1, "test", false /* isResumable*/,
-                true /* isAutoResumable */, true, false, null, false);
-        assertEquals(1, mDownloadNotificationService.getNotificationIds().size());
-        assertFalse(mDownloadForegroundServiceManager.mDownloadUpdateQueue.containsKey(
-                notificationId1));
-        assertFalse(mDownloadNotificationService.mDownloadsInProgress.contains(ID1));
-    }
-
-    @Test
-    @SmallTest
-    @Feature({"Download"})
-    public void testResumeAllPendingDownloads() {
-        // Queue a few pending downloads.
-        mDownloadSharedPreferenceHelper.addOrReplaceSharedPreferenceEntry(
-                buildEntryStringWithGuid(ID1, 3, "success", false, true));
-        mDownloadSharedPreferenceHelper.addOrReplaceSharedPreferenceEntry(
-                buildEntryStringWithGuid(ID2, 4, "failed", true, true));
-        mDownloadSharedPreferenceHelper.addOrReplaceSharedPreferenceEntry(
-                buildEntryStringWithGuid(ID3, 5, "nonresumable", true, false));
-
-        // Resume pending downloads when network is metered.
+        SharedPreferences sharedPrefs = ContextUtils.getAppSharedPreferences();
+        SharedPreferences.Editor editor = sharedPrefs.edit();
+        editor.putStringSet(
+                DownloadSharedPreferenceHelper.KEY_PENDING_DOWNLOAD_NOTIFICATIONS, notifications);
+        editor.apply();
+        startNotificationService();
+        DownloadNotificationService service = bindNotificationService();
         DownloadManagerService.disableNetworkListenerForTest();
+
+        final MockDownloadManagerService manager =
+                new MockDownloadManagerService(getSystemContext().getApplicationContext());
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                DownloadManagerService.setDownloadManagerService(manager);
+            }
+        });
         DownloadManagerService.setIsNetworkMeteredForTest(true);
-        mDownloadNotificationService.resumeAllPendingDownloads();
+        resumeAllDownloads(service);
+        assertEquals(1, manager.mDownloads.size());
+        assertEquals(manager.mDownloads.get(0).getDownloadInfo().getDownloadGuid(), guid2);
 
-        assertEquals(1, mDownloadNotificationService.mResumedDownloads.size());
-        assertEquals(ID2.id, mDownloadNotificationService.mResumedDownloads.get(0));
-
-        // Resume pending downloads when network is not metered.
-        // TODO(jming): Right now, assuming all downloads are resumed because of the way downloads
-        // in progress are tracked internally.
-        mDownloadNotificationService.mResumedDownloads.clear();
+        manager.mDownloads.clear();
         DownloadManagerService.setIsNetworkMeteredForTest(false);
-        mDownloadNotificationService.resumeAllPendingDownloads();
-        assertEquals(2, mDownloadNotificationService.mResumedDownloads.size());
+        resumeAllDownloads(service);
+        assertEquals(1, manager.mDownloads.size());
+        assertEquals(manager.mDownloads.get(0).getDownloadInfo().getDownloadGuid(), guid1);
+    }
 
-        mDownloadSharedPreferenceHelper.removeSharedPreferenceEntry(ID1);
-        mDownloadSharedPreferenceHelper.removeSharedPreferenceEntry(ID2);
-        mDownloadSharedPreferenceHelper.removeSharedPreferenceEntry(ID3);
+    /**
+     * Tests incognito download fails when browser gets killed.
+     */
+    @SmallTest
+    @Feature({"Download"})
+    public void testIncognitoDownloadCanceledOnServiceShutdown() throws Exception {
+        setupService();
+        Context mockContext = new AdvancedMockContext(getSystemContext());
+        getService().setContext(mockContext);
+        Set<String> notifications = new HashSet<>();
+        String uuid = UUID.randomUUID().toString();
+        notifications.add(buildEntryStringWithGuid(uuid, 1, "test1", true, true, true));
+        SharedPreferences sharedPrefs = ContextUtils.getAppSharedPreferences();
+        SharedPreferences.Editor editor = sharedPrefs.edit();
+        editor.putStringSet(
+                DownloadSharedPreferenceHelper.KEY_PENDING_DOWNLOAD_NOTIFICATIONS, notifications);
+        editor.apply();
+        startNotificationService();
+
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                getService().onTaskRemoved(new Intent());
+            }
+        });
+
+        assertTrue(getService().isPaused());
+        assertFalse(sharedPrefs.contains(
+                DownloadSharedPreferenceHelper.KEY_PENDING_DOWNLOAD_NOTIFICATIONS));
+    }
+
+    @SmallTest
+    @Feature({"Download"})
+    @RetryOnFailure
+    public void testServiceWillStopOnCompletedDownload() throws Exception {
+        // On versions of Android that use a foreground service, the service will currently die with
+        // the notifications.
+        if (DownloadNotificationService.useForegroundService()) return;
+
+        setupService();
+        startNotificationService();
+        DownloadNotificationService service = bindNotificationService();
+        ContentId id = LegacyHelpers.buildLegacyContentId(false, UUID.randomUUID().toString());
+        service.notifyDownloadProgress(id, "/path/to/test", Progress.createIndeterminateProgress(),
+                10L, 1000L, 10L, false, false, false, null);
+        assertFalse(service.hideSummaryNotificationIfNecessary(-1));
+        service.notifyDownloadSuccessful(
+                id, "/path/to/test", "test", 100L, false, false, true, null, null, null);
+        assertTrue(service.hideSummaryNotificationIfNecessary(-1));
+    }
+
+    @SmallTest
+    @Feature({"Download"})
+    @RetryOnFailure
+    public void testServiceWillStopOnFailedDownload() throws Exception {
+        // On versions of Android that use a foreground service, the service will currently die with
+        // the notifications.
+        if (DownloadNotificationService.useForegroundService()) return;
+
+        setupService();
+        startNotificationService();
+        DownloadNotificationService service = bindNotificationService();
+        ContentId id = LegacyHelpers.buildLegacyContentId(false, UUID.randomUUID().toString());
+        service.notifyDownloadProgress(id, "/path/to/test", Progress.createIndeterminateProgress(),
+                10L, 1000L, 10L, false, false, false, null);
+        assertFalse(service.hideSummaryNotificationIfNecessary(-1));
+        service.notifyDownloadFailed(id, "/path/to/test", null);
+        assertTrue(service.hideSummaryNotificationIfNecessary(-1));
+    }
+
+    @SmallTest
+    @Feature({"Download"})
+    @RetryOnFailure
+    public void testServiceWillStopOnCancelledDownload() throws Exception {
+        // On versions of Android that use a foreground service, the service will currently die with
+        // the notifications.
+        if (DownloadNotificationService.useForegroundService()) return;
+
+        setupService();
+        startNotificationService();
+        DownloadNotificationService service = bindNotificationService();
+        ContentId id = LegacyHelpers.buildLegacyContentId(false, UUID.randomUUID().toString());
+        service.notifyDownloadProgress(id, "/path/to/test", Progress.createIndeterminateProgress(),
+                10L, 1000L, 10L, false, false, false, null);
+        assertFalse(service.hideSummaryNotificationIfNecessary(-1));
+        service.notifyDownloadCanceled(id);
+        assertTrue(service.hideSummaryNotificationIfNecessary(-1));
+    }
+
+    @SmallTest
+    @Feature({"Download"})
+    public void testServiceWillNotStopOnInterruptedDownload() throws Exception {
+        // On versions of Android that use a foreground service, the service will currently die with
+        // the notifications.
+        if (DownloadNotificationService.useForegroundService()) return;
+
+        setupService();
+        startNotificationService();
+        DownloadNotificationService service = bindNotificationService();
+        ContentId id = LegacyHelpers.buildLegacyContentId(false, UUID.randomUUID().toString());
+        service.notifyDownloadProgress(id, "/path/to/test", Progress.createIndeterminateProgress(),
+                10L, 1000L, 10L, false, false, false, null);
+        assertFalse(service.hideSummaryNotificationIfNecessary(-1));
+        service.notifyDownloadPaused(id, "/path/to/test", true, true, false, false, null);
+        assertFalse(service.hideSummaryNotificationIfNecessary(-1));
+    }
+
+    @SmallTest
+    @Feature({"Download"})
+    public void testServiceWillNotStopOnPausedDownload() throws Exception {
+        // On versions of Android that use a foreground service, the service will currently die with
+        // the notifications.
+        if (DownloadNotificationService.useForegroundService()) return;
+
+        setupService();
+        startNotificationService();
+        DownloadNotificationService service = bindNotificationService();
+        ContentId id = LegacyHelpers.buildLegacyContentId(false, UUID.randomUUID().toString());
+        service.notifyDownloadProgress(id, "/path/to/test", Progress.createIndeterminateProgress(),
+                10L, 1000L, 10L, false, false, false, null);
+        assertFalse(service.hideSummaryNotificationIfNecessary(-1));
+        service.notifyDownloadPaused(id, "/path/to/test", true, false, false, false, null);
+        assertFalse(service.hideSummaryNotificationIfNecessary(-1));
+    }
+
+    @SmallTest
+    @Feature({"Download"})
+    @RetryOnFailure
+    public void testServiceWillNotStopWithOneOngoingDownload() throws Exception {
+        // On versions of Android that use a foreground service, the service will currently die with
+        // the notifications.
+        if (DownloadNotificationService.useForegroundService()) return;
+
+        setupService();
+        startNotificationService();
+        DownloadNotificationService service = bindNotificationService();
+        ContentId id1 = LegacyHelpers.buildLegacyContentId(false, UUID.randomUUID().toString());
+        ContentId id2 = LegacyHelpers.buildLegacyContentId(false, UUID.randomUUID().toString());
+
+        service.notifyDownloadProgress(id1, "/path/to/test", Progress.createIndeterminateProgress(),
+                10L, 1000L, 10L, false, false, false, null);
+        service.notifyDownloadProgress(id2, "/path/to/test", Progress.createIndeterminateProgress(),
+                10L, 1000L, 10L, false, false, false, null);
+        assertFalse(service.hideSummaryNotificationIfNecessary(-1));
+        service.notifyDownloadPaused(id1, "/path/to/test", true, false, false, false, null);
+        assertFalse(service.hideSummaryNotificationIfNecessary(-1));
+        service.notifyDownloadSuccessful(
+                id1, "/path/to/test", "test", 100L, false, false, true, null, null, null);
+        assertFalse(service.hideSummaryNotificationIfNecessary(-1));
+        service.notifyDownloadSuccessful(
+                id2, "/path/to/test", "test", 100L, false, false, true, null, null, null);
+        assertTrue(service.hideSummaryNotificationIfNecessary(-1));
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest2.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest2.java
new file mode 100644
index 0000000..7f5cb54
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest2.java
@@ -0,0 +1,205 @@
+// 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.
+
+package org.chromium.chrome.browser.download;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.content.SharedPreferences;
+import android.support.test.filters.SmallTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.ContextUtils;
+import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.components.offline_items_collection.ContentId;
+import org.chromium.components.offline_items_collection.LegacyHelpers;
+import org.chromium.components.offline_items_collection.OfflineItem.Progress;
+import org.chromium.components.offline_items_collection.OfflineItemProgressUnit;
+
+import java.util.UUID;
+
+/**
+ * Tests of {@link DownloadNotificationService2}.
+ */
+@RunWith(ChromeJUnit4ClassRunner.class)
+public class DownloadNotificationServiceTest2 {
+    private static final ContentId ID1 =
+            LegacyHelpers.buildLegacyContentId(false, UUID.randomUUID().toString());
+    private static final ContentId ID2 =
+            LegacyHelpers.buildLegacyContentId(false, UUID.randomUUID().toString());
+    private static final ContentId ID3 =
+            LegacyHelpers.buildLegacyContentId(false, UUID.randomUUID().toString());
+
+    private MockDownloadNotificationService2 mDownloadNotificationService;
+    private DownloadForegroundServiceManagerTest
+            .MockDownloadForegroundServiceManager mDownloadForegroundServiceManager;
+    private DownloadSharedPreferenceHelper mDownloadSharedPreferenceHelper;
+
+    private static DownloadSharedPreferenceEntry buildEntryStringWithGuid(ContentId contentId,
+            int notificationId, String fileName, boolean metered, boolean autoResume) {
+        return new DownloadSharedPreferenceEntry(
+                contentId, notificationId, false, metered, fileName, autoResume, false);
+    }
+
+    @Before
+    public void setUp() {
+        mDownloadNotificationService = new MockDownloadNotificationService2();
+        mDownloadForegroundServiceManager =
+                new DownloadForegroundServiceManagerTest.MockDownloadForegroundServiceManager();
+        mDownloadNotificationService.setDownloadForegroundServiceManager(
+                mDownloadForegroundServiceManager);
+        mDownloadSharedPreferenceHelper = DownloadSharedPreferenceHelper.getInstance();
+    }
+
+    @After
+    public void tearDown() {
+        SharedPreferences sharedPrefs = ContextUtils.getAppSharedPreferences();
+        SharedPreferences.Editor editor = sharedPrefs.edit();
+        editor.remove(DownloadSharedPreferenceHelper.KEY_PENDING_DOWNLOAD_NOTIFICATIONS);
+        editor.apply();
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Download"})
+    public void testBasicDownloadFlow() {
+        // Download is in-progress.
+        mDownloadNotificationService.notifyDownloadProgress(ID1, "test",
+                new Progress(1, 100L, OfflineItemProgressUnit.PERCENTAGE), 100L, 1L, 1L, true, true,
+                false, null);
+        mDownloadForegroundServiceManager.onServiceConnected();
+
+        assertEquals(1, mDownloadNotificationService.getNotificationIds().size());
+        int notificationId1 = mDownloadNotificationService.getLastNotificationId();
+        assertTrue(mDownloadForegroundServiceManager.mDownloadUpdateQueue.containsKey(
+                notificationId1));
+        assertTrue(mDownloadNotificationService.mDownloadsInProgress.contains(ID1));
+
+        // Download is paused.
+        mDownloadNotificationService.notifyDownloadPaused(ID1, "test", true /* isResumable*/,
+                false /* isAutoResumable */, true, false, null, false);
+
+        assertEquals(1, mDownloadNotificationService.getNotificationIds().size());
+        assertFalse(mDownloadForegroundServiceManager.mDownloadUpdateQueue.containsKey(
+                notificationId1));
+        assertFalse(mDownloadNotificationService.mDownloadsInProgress.contains(ID1));
+
+        // Download is again in-progress.
+        mDownloadNotificationService.notifyDownloadProgress(ID1, "test",
+                new Progress(20, 100L, OfflineItemProgressUnit.PERCENTAGE), 100L, 1L, 1L, true,
+                true, false, null);
+        mDownloadForegroundServiceManager.onServiceConnected();
+
+        assertEquals(1, mDownloadNotificationService.getNotificationIds().size());
+        assertTrue(mDownloadForegroundServiceManager.mDownloadUpdateQueue.containsKey(
+                notificationId1));
+        assertTrue(mDownloadNotificationService.mDownloadsInProgress.contains(ID1));
+
+        // Download is successful.
+        mDownloadNotificationService.notifyDownloadSuccessful(
+                ID1, "", "test", 1L, true, true, true, null, "", "");
+        assertEquals(1, mDownloadNotificationService.getNotificationIds().size());
+        assertFalse(mDownloadForegroundServiceManager.mDownloadUpdateQueue.containsKey(
+                notificationId1));
+        assertFalse(mDownloadNotificationService.mDownloadsInProgress.contains(ID1));
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Download"})
+    public void testDownloadPendingAndCancelled() {
+        // Download is in-progress.
+        mDownloadNotificationService.notifyDownloadProgress(ID1, "test",
+                new Progress(1, 100L, OfflineItemProgressUnit.PERCENTAGE), 100L, 1L, 1L, true, true,
+                false, null);
+        mDownloadForegroundServiceManager.onServiceConnected();
+
+        assertEquals(1, mDownloadNotificationService.getNotificationIds().size());
+        int notificationId1 = mDownloadNotificationService.getLastNotificationId();
+        assertTrue(mDownloadForegroundServiceManager.mDownloadUpdateQueue.containsKey(
+                notificationId1));
+        assertTrue(mDownloadNotificationService.mDownloadsInProgress.contains(ID1));
+
+        // Download is interrupted and now is pending.
+        mDownloadNotificationService.notifyDownloadPaused(ID1, "test", true /* isResumable */,
+                true /* isAutoResumable */, true, false, null, false);
+        assertEquals(1, mDownloadNotificationService.getNotificationIds().size());
+        assertTrue(mDownloadForegroundServiceManager.mDownloadUpdateQueue.containsKey(
+                notificationId1));
+        assertFalse(mDownloadNotificationService.mDownloadsInProgress.contains(ID1));
+
+        // Download is cancelled.
+        mDownloadNotificationService.notifyDownloadCanceled(ID1, false);
+
+        assertEquals(0, mDownloadNotificationService.getNotificationIds().size());
+        assertFalse(mDownloadForegroundServiceManager.mDownloadUpdateQueue.containsKey(
+                notificationId1));
+        assertFalse(mDownloadNotificationService.mDownloadsInProgress.contains(ID1));
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Download"})
+    public void testDownloadInterruptedAndFailed() {
+        // Download is in-progress.
+        mDownloadNotificationService.notifyDownloadProgress(ID1, "test",
+                new Progress(1, 100L, OfflineItemProgressUnit.PERCENTAGE), 100L, 1L, 1L, true, true,
+                false, null);
+        mDownloadForegroundServiceManager.onServiceConnected();
+
+        assertEquals(1, mDownloadNotificationService.getNotificationIds().size());
+        int notificationId1 = mDownloadNotificationService.getLastNotificationId();
+        assertTrue(mDownloadForegroundServiceManager.mDownloadUpdateQueue.containsKey(
+                notificationId1));
+        assertTrue(mDownloadNotificationService.mDownloadsInProgress.contains(ID1));
+
+        // Download is interrupted but because it is not resumable, fails.
+        mDownloadNotificationService.notifyDownloadPaused(ID1, "test", false /* isResumable*/,
+                true /* isAutoResumable */, true, false, null, false);
+        assertEquals(1, mDownloadNotificationService.getNotificationIds().size());
+        assertFalse(mDownloadForegroundServiceManager.mDownloadUpdateQueue.containsKey(
+                notificationId1));
+        assertFalse(mDownloadNotificationService.mDownloadsInProgress.contains(ID1));
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Download"})
+    public void testResumeAllPendingDownloads() {
+        // Queue a few pending downloads.
+        mDownloadSharedPreferenceHelper.addOrReplaceSharedPreferenceEntry(
+                buildEntryStringWithGuid(ID1, 3, "success", false, true));
+        mDownloadSharedPreferenceHelper.addOrReplaceSharedPreferenceEntry(
+                buildEntryStringWithGuid(ID2, 4, "failed", true, true));
+        mDownloadSharedPreferenceHelper.addOrReplaceSharedPreferenceEntry(
+                buildEntryStringWithGuid(ID3, 5, "nonresumable", true, false));
+
+        // Resume pending downloads when network is metered.
+        DownloadManagerService.disableNetworkListenerForTest();
+        DownloadManagerService.setIsNetworkMeteredForTest(true);
+        mDownloadNotificationService.resumeAllPendingDownloads();
+
+        assertEquals(1, mDownloadNotificationService.mResumedDownloads.size());
+        assertEquals(ID2.id, mDownloadNotificationService.mResumedDownloads.get(0));
+
+        // Resume pending downloads when network is not metered.
+        // TODO(jming): Right now, assuming all downloads are resumed because of the way downloads
+        // in progress are tracked internally.
+        mDownloadNotificationService.mResumedDownloads.clear();
+        DownloadManagerService.setIsNetworkMeteredForTest(false);
+        mDownloadNotificationService.resumeAllPendingDownloads();
+        assertEquals(2, mDownloadNotificationService.mResumedDownloads.size());
+
+        mDownloadSharedPreferenceHelper.removeSharedPreferenceEntry(ID1);
+        mDownloadSharedPreferenceHelper.removeSharedPreferenceEntry(ID2);
+        mDownloadSharedPreferenceHelper.removeSharedPreferenceEntry(ID3);
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/MockDownloadNotificationService.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/MockDownloadNotificationService.java
index 7f1de07..ea483c9 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/MockDownloadNotificationService.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/MockDownloadNotificationService.java
@@ -4,19 +4,18 @@
 
 package org.chromium.chrome.browser.download;
 
-import static org.chromium.chrome.browser.notifications.NotificationConstants.DEFAULT_NOTIFICATION_ID;
-
 import android.app.Notification;
-import android.content.Intent;
+import android.content.Context;
 import android.graphics.Bitmap;
+import android.util.Pair;
 
 import org.chromium.base.ThreadUtils;
-import org.chromium.chrome.browser.util.IntentUtils;
 import org.chromium.components.offline_items_collection.ContentId;
 import org.chromium.components.offline_items_collection.OfflineItem.Progress;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.Callable;
 
 /**
  * Mock class to DownloadNotificationService for testing purpose.
@@ -24,9 +23,46 @@
 public class MockDownloadNotificationService extends DownloadNotificationService {
     private final List<Integer> mNotificationIds = new ArrayList<Integer>();
     private boolean mPaused = false;
-    private int mLastNotificationId = DEFAULT_NOTIFICATION_ID;
+    private Context mContext;
+    private int mLastNotificationId;
 
-    List<String> mResumedDownloads = new ArrayList<>();
+    void setContext(Context context) {
+        mContext = context;
+    }
+
+    @Override
+    public void stopForegroundInternal(boolean killNotification) {
+        if (!useForegroundService()) return;
+        if (killNotification) mNotificationIds.clear();
+    }
+
+    @Override
+    public void startForegroundInternal() {}
+
+    @Override
+    public void cancelOffTheRecordDownloads() {
+        super.cancelOffTheRecordDownloads();
+        mPaused = true;
+    }
+
+    @Override
+    boolean hasDownloadNotificationsInternal(int notificationIdToIgnore) {
+        if (!useForegroundService()) return false;
+        // Cancelling notifications here is synchronous, so we don't really have to worry about
+        // {@code notificationIdToIgnore}, but address it properly anyway.
+        if (mNotificationIds.size() == 1 && notificationIdToIgnore != -1) {
+            return !mNotificationIds.contains(notificationIdToIgnore);
+        }
+
+        return !mNotificationIds.isEmpty();
+    }
+
+    @Override
+    void updateSummaryIconInternal(
+            int removedNotificationId, Pair<Integer, Notification> addedNotification) {}
+
+    @Override
+    void cancelSummaryNotification() {}
 
     @Override
     void updateNotification(int id, Notification notification) {
@@ -44,25 +80,34 @@
         return mNotificationIds;
     }
 
-    public int getLastNotificationId() {
-        return mLastNotificationId;
-    }
-
     @Override
     public void cancelNotification(int notificationId, ContentId id) {
         super.cancelNotification(notificationId, id);
         mNotificationIds.remove(Integer.valueOf(notificationId));
     }
 
+    public int getLastAddedNotificationId() {
+        return mLastNotificationId;
+    }
+
+    @Override
+    public Context getApplicationContext() {
+        return mContext == null ? super.getApplicationContext() : mContext;
+    }
+
     @Override
     public int notifyDownloadSuccessful(final ContentId id, final String filePath,
             final String fileName, final long systemDownloadId, final boolean isOffTheRecord,
             final boolean isSupportedMimeType, final boolean isOpenable, final Bitmap icon,
             final String originalUrl, final String referrer) {
-        return ThreadUtils.runOnUiThreadBlockingNoException(
-                () -> MockDownloadNotificationService.super.notifyDownloadSuccessful(id, filePath,
+        return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<Integer>() {
+            @Override
+            public Integer call() throws Exception {
+                return MockDownloadNotificationService.super.notifyDownloadSuccessful(id, filePath,
                         fileName, systemDownloadId, isOffTheRecord, isSupportedMimeType, isOpenable,
-                        icon, originalUrl, referrer));
+                        icon, originalUrl, referrer);
+            }
+        });
     }
 
     @Override
@@ -70,42 +115,34 @@
             final Progress progress, final long bytesReceived, final long timeRemainingInMillis,
             final long startTime, final boolean isOffTheRecord,
             final boolean canDownloadWhileMetered, final boolean isTransient, final Bitmap icon) {
-        ThreadUtils.runOnUiThreadBlocking(
-                () -> MockDownloadNotificationService.super.notifyDownloadProgress(id, fileName,
-                        progress,
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                MockDownloadNotificationService.super.notifyDownloadProgress(id, fileName, progress,
                         bytesReceived, timeRemainingInMillis, startTime, isOffTheRecord,
-                        canDownloadWhileMetered, isTransient, icon));
-    }
-
-    @Override
-    void notifyDownloadPaused(ContentId id, String fileName, boolean isResumable,
-            boolean isAutoResumable, boolean isOffTheRecord, boolean isTransient, Bitmap icon,
-            boolean hasUserGesture) {
-        ThreadUtils.runOnUiThreadBlocking(
-                ()
-                        -> MockDownloadNotificationService.super.notifyDownloadPaused(id, fileName,
-                                isResumable, isAutoResumable, isOffTheRecord, isTransient, icon,
-                                hasUserGesture));
+                        canDownloadWhileMetered, isTransient, icon);
+            }
+        });
     }
 
     @Override
     public void notifyDownloadFailed(final ContentId id, final String fileName, final Bitmap icon) {
-        ThreadUtils.runOnUiThreadBlocking(
-                () -> MockDownloadNotificationService.super.notifyDownloadFailed(id, fileName,
-                        icon));
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                MockDownloadNotificationService.super.notifyDownloadFailed(id, fileName, icon);
+            }
+        });
     }
 
     @Override
-    public void notifyDownloadCanceled(final ContentId id, boolean hasUserGesture) {
-        ThreadUtils.runOnUiThreadBlocking(
-                ()
-                        -> MockDownloadNotificationService.super.notifyDownloadCanceled(
-                                id, hasUserGesture));
-    }
-
-    @Override
-    void resumeDownload(Intent intent) {
-        mResumedDownloads.add(IntentUtils.safeGetStringExtra(intent, EXTRA_DOWNLOAD_CONTENTID_ID));
+    public void notifyDownloadCanceled(final ContentId id) {
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                MockDownloadNotificationService.super.notifyDownloadCanceled(id);
+            }
+        });
     }
 }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/MockDownloadNotificationService2.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/MockDownloadNotificationService2.java
new file mode 100644
index 0000000..8013b01f
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/MockDownloadNotificationService2.java
@@ -0,0 +1,112 @@
+// 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.
+
+package org.chromium.chrome.browser.download;
+
+import static org.chromium.chrome.browser.notifications.NotificationConstants.DEFAULT_NOTIFICATION_ID;
+
+import android.app.Notification;
+import android.content.Intent;
+import android.graphics.Bitmap;
+
+import org.chromium.base.ThreadUtils;
+import org.chromium.chrome.browser.util.IntentUtils;
+import org.chromium.components.offline_items_collection.ContentId;
+import org.chromium.components.offline_items_collection.OfflineItem.Progress;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Mock class to DownloadNotificationService for testing purpose.
+ */
+public class MockDownloadNotificationService2 extends DownloadNotificationService2 {
+    private final List<Integer> mNotificationIds = new ArrayList<Integer>();
+    private boolean mPaused = false;
+    private int mLastNotificationId = DEFAULT_NOTIFICATION_ID;
+
+    List<String> mResumedDownloads = new ArrayList<>();
+
+    @Override
+    void updateNotification(int id, Notification notification) {
+        if (!mNotificationIds.contains(id)) {
+            mNotificationIds.add(id);
+            mLastNotificationId = id;
+        }
+    }
+
+    public boolean isPaused() {
+        return mPaused;
+    }
+
+    public List<Integer> getNotificationIds() {
+        return mNotificationIds;
+    }
+
+    public int getLastNotificationId() {
+        return mLastNotificationId;
+    }
+
+    @Override
+    public void cancelNotification(int notificationId, ContentId id) {
+        super.cancelNotification(notificationId, id);
+        mNotificationIds.remove(Integer.valueOf(notificationId));
+    }
+
+    @Override
+    public int notifyDownloadSuccessful(final ContentId id, final String filePath,
+            final String fileName, final long systemDownloadId, final boolean isOffTheRecord,
+            final boolean isSupportedMimeType, final boolean isOpenable, final Bitmap icon,
+            final String originalUrl, final String referrer) {
+        return ThreadUtils.runOnUiThreadBlockingNoException(
+                ()
+                        -> MockDownloadNotificationService2.super.notifyDownloadSuccessful(id,
+                                filePath, fileName, systemDownloadId, isOffTheRecord,
+                                isSupportedMimeType, isOpenable, icon, originalUrl, referrer));
+    }
+
+    @Override
+    public void notifyDownloadProgress(final ContentId id, final String fileName,
+            final Progress progress, final long bytesReceived, final long timeRemainingInMillis,
+            final long startTime, final boolean isOffTheRecord,
+            final boolean canDownloadWhileMetered, final boolean isTransient, final Bitmap icon) {
+        ThreadUtils.runOnUiThreadBlocking(
+                ()
+                        -> MockDownloadNotificationService2.super.notifyDownloadProgress(id,
+                                fileName, progress, bytesReceived, timeRemainingInMillis, startTime,
+                                isOffTheRecord, canDownloadWhileMetered, isTransient, icon));
+    }
+
+    @Override
+    void notifyDownloadPaused(ContentId id, String fileName, boolean isResumable,
+            boolean isAutoResumable, boolean isOffTheRecord, boolean isTransient, Bitmap icon,
+            boolean hasUserGesture) {
+        ThreadUtils.runOnUiThreadBlocking(
+                ()
+                        -> MockDownloadNotificationService2.super.notifyDownloadPaused(id, fileName,
+                                isResumable, isAutoResumable, isOffTheRecord, isTransient, icon,
+                                hasUserGesture));
+    }
+
+    @Override
+    public void notifyDownloadFailed(final ContentId id, final String fileName, final Bitmap icon) {
+        ThreadUtils.runOnUiThreadBlocking(
+                ()
+                        -> MockDownloadNotificationService2.super.notifyDownloadFailed(
+                                id, fileName, icon));
+    }
+
+    @Override
+    public void notifyDownloadCanceled(final ContentId id, boolean hasUserGesture) {
+        ThreadUtils.runOnUiThreadBlocking(
+                ()
+                        -> MockDownloadNotificationService2.super.notifyDownloadCanceled(
+                                id, hasUserGesture));
+    }
+
+    @Override
+    void resumeDownload(Intent intent) {
+        mResumedDownloads.add(IntentUtils.safeGetStringExtra(intent, EXTRA_DOWNLOAD_CONTENTID_ID));
+    }
+}
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 d13e7f6e..6932908 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
@@ -117,7 +117,7 @@
 
     private FrameLayout mContentView;
     private SnippetArticleViewHolder mSuggestion;
-    private SignInPromo.ViewHolder mSigninPromo;
+    private SignInPromo.GenericPromoViewHolder mSigninPromo;
 
     private UiConfig mUiConfig;
 
@@ -282,7 +282,8 @@
             mRecyclerView.init(mUiConfig, contextMenuManager);
             mRecyclerView.setAdapter(mAdapter);
 
-            mSigninPromo = new SignInPromo.ViewHolder(mRecyclerView, contextMenuManager, mUiConfig);
+            mSigninPromo = new SignInPromo.GenericPromoViewHolder(
+                    mRecyclerView, contextMenuManager, mUiConfig);
             mSigninPromo.onBindViewHolder(new SignInPromo(mUiDelegate));
             mContentView.addView(mSigninPromo.itemView);
         });
@@ -352,7 +353,7 @@
     @Before
     public void setUp() throws Exception {
         mActivityTestRule.startMainActivityOnBlankPage();
-        ChromePreferenceManager.getInstance().setNewTabPageSigninPromoDismissed(true);
+        ChromePreferenceManager.getInstance().setNewTabPageGenericSigninPromoDismissed(true);
         mThumbnailProvider = new MockThumbnailProvider();
         mSnippetsSource = new FakeSuggestionsSource();
         mSuggestionsDeps.getFactory().thumbnailProvider = mThumbnailProvider;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrInputTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrInputTest.java
index 6601bce7..c8c73487 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrInputTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrInputTest.java
@@ -211,4 +211,25 @@
             }
         });
     }
+
+    /**
+     * Verifies that pressing the Daydream controller's 'app' button causes the user to exit
+     * WebVR presentation even when the page is not submitting frames.
+     */
+    @Test
+    @MediumTest
+    @Restriction(RESTRICTION_TYPE_VIEWER_DAYDREAM)
+    @RetryOnFailure(message = "Very rarely, button press not registered (race condition?)")
+    public void testAppButtonAfterPageStopsSubmitting() throws InterruptedException {
+        mVrTestFramework.loadUrlAndAwaitInitialization(
+                VrTestFramework.getHtmlTestFile("webvr_page_submits_once"), PAGE_LOAD_TIMEOUT_S);
+        VrTransitionUtils.enterPresentationOrFail(mVrTestFramework.getFirstTabCvc());
+        // Wait for page to stop submitting frames.
+        mVrTestFramework.waitOnJavaScriptStep(mVrTestFramework.getFirstTabWebContents());
+        EmulatedVrController controller = new EmulatedVrController(mVrTestRule.getActivity());
+        controller.pressReleaseAppButton();
+        Assert.assertTrue("App button exited WebVR presentation",
+                mVrTestFramework.pollJavaScriptBoolean("!vrDisplay.isPresenting",
+                        POLL_TIMEOUT_SHORT_MS, mVrTestFramework.getFirstTabWebContents()));
+    }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappActionsNotificationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappActionsNotificationTest.java
index 8ffab5f..c914b7c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappActionsNotificationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappActionsNotificationTest.java
@@ -32,7 +32,6 @@
 import org.chromium.components.url_formatter.UrlFormatter;
 import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
-import org.chromium.net.test.EmbeddedTestServerRule;
 
 /**
  * Tests for a standalone Web App notification governed by {@link WebappActionsNotificationManager}.
@@ -45,13 +44,10 @@
     @Rule
     public final WebappActivityTestRule mActivityTestRule = new WebappActivityTestRule();
 
-    @Rule
-    public EmbeddedTestServerRule mTestServerRule = new EmbeddedTestServerRule();
-
     @Before
     public void startWebapp() throws Exception {
         mActivityTestRule.startWebappActivity(mActivityTestRule.createIntent().putExtra(
-                ShortcutHelper.EXTRA_URL, mTestServerRule.getServer().getURL(WEB_APP_PATH)));
+                ShortcutHelper.EXTRA_URL, mActivityTestRule.getUrlFromTestServer(WEB_APP_PATH)));
         mActivityTestRule.waitUntilSplashscreenHides();
     }
 
@@ -67,8 +63,8 @@
         Assert.assertNotNull(notification);
         Assert.assertEquals("webapp short name runs in Chrome",
                 notification.extras.getString(Notification.EXTRA_TITLE));
-        Assert.assertEquals(
-                UrlFormatter.formatUrlForDisplay(mTestServerRule.getServer().getURL(WEB_APP_PATH)),
+        Assert.assertEquals(UrlFormatter.formatUrlForDisplay(
+                                    mActivityTestRule.getUrlFromTestServer(WEB_APP_PATH)),
                 notification.extras.getString(Notification.EXTRA_TEXT));
         Assert.assertEquals("Share", notification.actions[0].title);
         Assert.assertEquals("Open in Chrome", notification.actions[1].title);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappActivityTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappActivityTestRule.java
index 159251d..1a505bdf 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappActivityTestRule.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappActivityTestRule.java
@@ -4,22 +4,24 @@
 
 package org.chromium.chrome.browser.webapps;
 
-import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout;
-
 import android.content.Intent;
 import android.net.Uri;
 import android.view.ViewGroup;
 
 import org.junit.Assert;
+import org.junit.Rule;
 import org.junit.runner.Description;
 import org.junit.runners.model.Statement;
 
+import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout;
+
 import org.chromium.base.test.util.UrlUtils;
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.ShortcutHelper;
 import org.chromium.chrome.test.ChromeActivityTestRule;
 import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
+import org.chromium.net.test.EmbeddedTestServerRule;
 
 /**
  * Custom {@link ChromeActivityTestRule} for tests using {@link WebappActivity}.
@@ -64,10 +66,17 @@
             + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
             + "AAAAAAAAAOA3AvAAAdln8YgAAAAASUVORK5CYII=";
 
+    @Rule
+    private EmbeddedTestServerRule mTestServerRule = new EmbeddedTestServerRule();
+
     public WebappActivityTestRule() {
         super(WebappActivity0.class);
     }
 
+    public String getUrlFromTestServer(String relativeUrl) {
+        return mTestServerRule.getServer().getURL(relativeUrl);
+    }
+
     /**
      * Creates the Intent that starts the WebAppActivity. This is meant to be overriden by other
      * tests in order for them to pass some specific values, but it defaults to a web app that just
@@ -86,7 +95,7 @@
 
     @Override
     public Statement apply(final Statement base, Description description) {
-        return new Statement() {
+        Statement webappTestRuleStatement = new Statement() {
             @Override
             public void evaluate() throws Throwable {
                 // Register the webapp so when the data storage is opened, the test doesn't crash.
@@ -95,12 +104,13 @@
                 WebappRegistry.getInstance().register(WEBAPP_ID, callback);
                 callback.waitForCallback(0);
                 callback.getStorage().updateFromShortcutIntent(createIntent());
-
                 base.evaluate();
-
                 WebappRegistry.getInstance().clearForTesting();
             }
         };
+
+        Statement testServerStatement = mTestServerRule.apply(webappTestRuleStatement, description);
+        return super.apply(testServerStatement, description);
     }
 
     /**
@@ -141,6 +151,46 @@
     }
 
     /**
+     * Starts up the WebappActivity and sets up the test observer.
+     * Wait till Splashscreen full loaded.
+     */
+    public final ViewGroup startWebappActivityAndWaitForSplashScreen() throws Exception {
+        return startWebappActivityAndWaitForSplashScreen(createIntent());
+    }
+
+    /**
+     * Starts up the WebappActivity and sets up the test observer.
+     * Wait till Splashscreen full loaded.
+     * Intent url is modified to one that takes more time to load.
+     */
+    public final ViewGroup startWebappActivityAndWaitForSplashScreen(Intent intent)
+            throws Exception {
+        // Reset the url to one that takes more time to load.
+        // This is to make sure splash screen won't disappear during test.
+        intent.putExtra(ShortcutHelper.EXTRA_URL, getUrlFromTestServer("/slow?2"));
+        launchActivity(intent);
+        getInstrumentation().waitForIdleSync();
+        CriteriaHelper.pollInstrumentationThread(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                // we are waiting for WebappActivity#getActivityTab() to be non-null because we want
+                // to ensure that native has been loaded.
+                // We also wait till the splash screen has finished initializing.
+                ViewGroup splashScreen = getActivity().getSplashScreenForTests();
+                return getActivity().getActivityTab() != null && splashScreen != null
+                        && splashScreen.getChildCount() > 0;
+            }
+        }, STARTUP_TIMEOUT, CriteriaHelper.DEFAULT_POLLING_INTERVAL);
+
+        getInstrumentation().waitForIdleSync();
+        ViewGroup splashScreen = getActivity().getSplashScreenForTests();
+        if (splashScreen == null) {
+            Assert.fail("No splash screen available.");
+        }
+        return splashScreen;
+    }
+
+    /**
      * Waits for the splash screen to be hidden.
      */
     public void waitUntilSplashscreenHides() {
@@ -152,21 +202,6 @@
         }, STARTUP_TIMEOUT, CriteriaHelper.DEFAULT_POLLING_INTERVAL);
     }
 
-    public ViewGroup waitUntilSplashScreenAppears() {
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return getActivity().getSplashScreenForTests() != null;
-            }
-        });
-
-        ViewGroup splashScreen = getActivity().getSplashScreenForTests();
-        if (splashScreen == null) {
-            Assert.fail("No splash screen available.");
-        }
-        return splashScreen;
-    }
-
     public boolean isSplashScreenVisible() {
         return getActivity().getSplashScreenForTests() != null;
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappDisplayModeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappDisplayModeTest.java
index c586e4c..b153219 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappDisplayModeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappDisplayModeTest.java
@@ -23,7 +23,6 @@
 import org.chromium.chrome.browser.ShortcutHelper;
 import org.chromium.chrome.browser.omnibox.UrlBar;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
-import org.chromium.net.test.EmbeddedTestServerRule;
 
 /**
  * Test for various Display Modes of Web Apps.
@@ -38,9 +37,6 @@
     @Rule
     public final WebappActivityTestRule mActivityTestRule = new WebappActivityTestRule();
 
-    @Rule
-    public EmbeddedTestServerRule mTestServerRule = new EmbeddedTestServerRule();
-
     @Test
     @SmallTest
     @Feature({"Webapps"})
@@ -74,7 +70,7 @@
         Assert.assertEquals("Web App title should be displayed on the title bar",
                 WEB_APP_PAGE_TITLE, ((TextView) activity.findViewById(R.id.title_bar)).getText());
         Assert.assertEquals("URL Bar should display URL authority",
-                Uri.parse(mTestServerRule.getServer().getURL(WEB_APP_PATH)).getAuthority(),
+                Uri.parse(mActivityTestRule.getUrlFromTestServer(WEB_APP_PATH)).getAuthority(),
                 ((UrlBar) activity.findViewById(R.id.url_bar)).getText().toString());
         Assert.assertEquals("CCT Close button should not be visible", View.GONE,
                 activity.findViewById(R.id.close_button).getVisibility());
@@ -84,7 +80,7 @@
         mActivityTestRule.startWebappActivity(
                 mActivityTestRule.createIntent()
                         .putExtra(ShortcutHelper.EXTRA_URL,
-                                mTestServerRule.getServer().getURL(WEB_APP_PATH))
+                                mActivityTestRule.getUrlFromTestServer(WEB_APP_PATH))
                         .putExtra(ShortcutHelper.EXTRA_DISPLAY_MODE, displayMode)
                         .putExtra(ShortcutHelper.EXTRA_THEME_COLOR, (long) Color.CYAN));
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappNavigationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappNavigationTest.java
index 3400e61..45af0d8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappNavigationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappNavigationTest.java
@@ -40,7 +40,6 @@
 import org.chromium.content.browser.test.util.CriteriaHelper;
 import org.chromium.content.browser.test.util.DOMUtils;
 import org.chromium.content_public.browser.WebContents;
-import org.chromium.net.test.EmbeddedTestServerRule;
 import org.chromium.ui.base.PageTransition;
 
 /**
@@ -58,9 +57,6 @@
     @Rule
     public final WebappActivityTestRule mActivityTestRule = new WebappActivityTestRule();
 
-    @Rule
-    public EmbeddedTestServerRule mTestServerRule = new EmbeddedTestServerRule();
-
     @Test
     @SmallTest
     @Feature({"Webapps"})
@@ -122,7 +118,7 @@
     public void testInScopeNewTabLinkOpensInCct() throws Exception {
         runWebappActivityAndWaitForIdle(mActivityTestRule.createIntent().putExtra(
                 ShortcutHelper.EXTRA_THEME_COLOR, (long) Color.CYAN));
-        addAnchor("testId", mTestServerRule.getServer().getURL(IN_SCOPE_PAGE_PATH), "_blank");
+        addAnchor("testId", mActivityTestRule.getUrlFromTestServer(IN_SCOPE_PAGE_PATH), "_blank");
         DOMUtils.clickNode(
                 mActivityTestRule.getActivity().getActivityTab().getContentViewCore(), "testId");
         CustomTabActivity customTab = waitFor(CustomTabActivity.class);
@@ -167,7 +163,7 @@
     public void testInScopeNavigationStaysInWebapp() throws Exception {
         runWebappActivityAndWaitForIdle(mActivityTestRule.createIntent());
 
-        String otherPageUrl = mTestServerRule.getServer().getURL(IN_SCOPE_PAGE_PATH);
+        String otherPageUrl = mActivityTestRule.getUrlFromTestServer(IN_SCOPE_PAGE_PATH);
         mActivityTestRule.loadUrlInTab(otherPageUrl, PageTransition.LINK,
                 mActivityTestRule.getActivity().getActivityTab());
 
@@ -220,7 +216,7 @@
         mActivityTestRule.waitUntilIdle(tabbedChrome);
 
         Assert.assertEquals("Tab in tabbed activity should show the Web App page",
-                mTestServerRule.getServer().getURL(WEB_APP_PATH),
+                mActivityTestRule.getUrlFromTestServer(WEB_APP_PATH),
                 tabbedChrome.getActivityTab().getUrl());
         Assert.assertSame("WebContents should be reparented from Web App to tabbed Chrome",
                 webAppWebContents, tabbedChrome.getActivityTab().getWebContents());
@@ -261,7 +257,7 @@
 
     private void runWebappActivityAndWaitForIdle(Intent intent) throws Exception {
         mActivityTestRule.startWebappActivity(intent.putExtra(
-                ShortcutHelper.EXTRA_URL, mTestServerRule.getServer().getURL(WEB_APP_PATH)));
+                ShortcutHelper.EXTRA_URL, mActivityTestRule.getUrlFromTestServer(WEB_APP_PATH)));
 
         mActivityTestRule.waitUntilSplashscreenHides();
         mActivityTestRule.waitUntilIdle();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenBackgroundColorTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenBackgroundColorTest.java
index 30369428..54c5e05a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenBackgroundColorTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenBackgroundColorTest.java
@@ -37,13 +37,12 @@
     @SmallTest
     @Feature({"Webapps"})
     public void testShowBackgroundColorAndRecordUma() throws Exception {
-        mActivityTestRule.startWebappActivity(
+        ViewGroup splashScreen = mActivityTestRule.startWebappActivityAndWaitForSplashScreen(
                 mActivityTestRule
                         .createIntent()
                         // This is setting Color.GREEN with 50% opacity.
                         .putExtra(ShortcutHelper.EXTRA_BACKGROUND_COLOR, 0x8000FF00L));
 
-        ViewGroup splashScreen = mActivityTestRule.waitUntilSplashScreenAppears();
         ColorDrawable background = (ColorDrawable) splashScreen.getBackground();
 
         Assert.assertEquals(Color.GREEN, background.getColor());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenHomescreenIconTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenHomescreenIconTest.java
index 0e5e6c18..d8e2b58 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenHomescreenIconTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenHomescreenIconTest.java
@@ -19,7 +19,6 @@
 import org.chromium.base.metrics.RecordHistogram;
 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.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.ShortcutHelper;
@@ -37,19 +36,21 @@
     @Rule
     public final WebappActivityTestRule mActivityTestRule = new WebappActivityTestRule();
 
+    private ViewGroup mSplashScreen;
+
     @Before
     public void setUp() throws Exception {
-        mActivityTestRule.startWebappActivity(mActivityTestRule.createIntent().putExtra(
-                ShortcutHelper.EXTRA_ICON, WebappActivityTestRule.TEST_ICON));
+        mSplashScreen = mActivityTestRule.startWebappActivityAndWaitForSplashScreen(
+                mActivityTestRule.createIntent().putExtra(
+                        ShortcutHelper.EXTRA_ICON, WebappActivityTestRule.TEST_ICON));
     }
 
     @Test
     @SmallTest
     @Feature({"Webapps"})
     public void testShowFallbackIcon() {
-        ViewGroup splashScreen = mActivityTestRule.waitUntilSplashScreenAppears();
-        ImageView splashImage = (ImageView) splashScreen.findViewById(
-                R.id.webapp_splash_screen_icon);
+        ImageView splashImage =
+                (ImageView) mSplashScreen.findViewById(R.id.webapp_splash_screen_icon);
         BitmapDrawable drawable = (BitmapDrawable) splashImage.getDrawable();
 
         Assert.assertEquals(192, drawable.getBitmap().getWidth());
@@ -59,7 +60,6 @@
     @Test
     @SmallTest
     @Feature({"Webapps"})
-    @RetryOnFailure
     public void testUmaFallbackIcon() {
         Assert.assertEquals(1,
                 RecordHistogram.getHistogramValueCountForTesting(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenIconTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenIconTest.java
index a7c46b1..a8fc4b5 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenIconTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenIconTest.java
@@ -19,7 +19,6 @@
 import org.chromium.base.metrics.RecordHistogram;
 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.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.ShortcutHelper;
@@ -33,27 +32,28 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
         ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG})
-@RetryOnFailure
 public class WebappSplashScreenIconTest {
     @Rule
     public final WebappActivityTestRule mActivityTestRule = new WebappActivityTestRule();
 
+    private ViewGroup mSplashScreen;
+
     @Before
     public void setUp() throws Exception {
         WebappRegistry.getInstance()
                 .getWebappDataStorage(WebappActivityTestRule.WEBAPP_ID)
                 .updateSplashScreenImage(WebappActivityTestRule.TEST_SPLASH_ICON);
-        mActivityTestRule.startWebappActivity(mActivityTestRule.createIntent().putExtra(
-                ShortcutHelper.EXTRA_ICON, WebappActivityTestRule.TEST_ICON));
+        mSplashScreen = mActivityTestRule.startWebappActivityAndWaitForSplashScreen(
+                mActivityTestRule.createIntent().putExtra(
+                        ShortcutHelper.EXTRA_ICON, WebappActivityTestRule.TEST_ICON));
     }
 
     @Test
     @SmallTest
     @Feature({"Webapps"})
     public void testShowSplashIcon() {
-        ViewGroup splashScreen = mActivityTestRule.waitUntilSplashScreenAppears();
-        ImageView splashImage = (ImageView) splashScreen.findViewById(
-                R.id.webapp_splash_screen_icon);
+        ImageView splashImage =
+                (ImageView) mSplashScreen.findViewById(R.id.webapp_splash_screen_icon);
         BitmapDrawable drawable = (BitmapDrawable) splashImage.getDrawable();
 
         Assert.assertEquals(512, drawable.getBitmap().getWidth());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenTest.java
index bae3d04..4a9e13a0 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenTest.java
@@ -27,7 +27,6 @@
 import org.chromium.base.metrics.RecordHistogram;
 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.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.ShortcutHelper;
@@ -69,10 +68,8 @@
     @Test
     @SmallTest
     @Feature({"Webapps"})
-    @RetryOnFailure
     public void testDefaultBackgroundColor() throws Exception {
-        mActivityTestRule.startWebappActivity();
-        ViewGroup splashScreen = mActivityTestRule.waitUntilSplashScreenAppears();
+        ViewGroup splashScreen = mActivityTestRule.startWebappActivityAndWaitForSplashScreen();
         ColorDrawable background = (ColorDrawable) splashScreen.getBackground();
 
         Assert.assertEquals(
@@ -85,9 +82,8 @@
     @SmallTest
     @Feature({"Webapps"})
     @TargetApi(Build.VERSION_CODES.LOLLIPOP)
-    @RetryOnFailure
     public void testThemeColorWhenNotSpecified() throws Exception {
-        mActivityTestRule.startWebappActivity();
+        mActivityTestRule.startWebappActivityAndWaitForSplashScreen();
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return;
 
         Assert.assertEquals(
@@ -97,9 +93,8 @@
     @Test
     @SmallTest
     @Feature({"Webapps"})
-    @RetryOnFailure
     public void testHidesAfterFirstPaint() throws Exception {
-        mActivityTestRule.startWebappActivity();
+        mActivityTestRule.startWebappActivityAndWaitForSplashScreen();
         Assert.assertTrue(mActivityTestRule.isSplashScreenVisible());
 
         ThreadUtils.runOnUiThread(new Runnable() {
@@ -116,9 +111,8 @@
     @Test
     @SmallTest
     @Feature({"Webapps"})
-    @RetryOnFailure
     public void testHidesAfterCrash() throws Throwable {
-        mActivityTestRule.startWebappActivity();
+        mActivityTestRule.startWebappActivityAndWaitForSplashScreen();
         Assert.assertTrue(mActivityTestRule.isSplashScreenVisible());
 
         ThreadUtils.runOnUiThread(new Runnable() {
@@ -134,9 +128,8 @@
     @Test
     @SmallTest
     @Feature({"Webapps"})
-    @RetryOnFailure
     public void testHidesAfterLoadCompletes() throws Exception {
-        mActivityTestRule.startWebappActivity();
+        mActivityTestRule.startWebappActivityAndWaitForSplashScreen();
         Assert.assertTrue(mActivityTestRule.isSplashScreenVisible());
 
         ThreadUtils.runOnUiThread(new Runnable() {
@@ -153,9 +146,8 @@
     @Test
     @SmallTest
     @Feature({"Webapps"})
-    @RetryOnFailure
     public void testHidesAfterLoadFails() throws Exception {
-        mActivityTestRule.startWebappActivity();
+        mActivityTestRule.startWebappActivityAndWaitForSplashScreen();
         Assert.assertTrue(mActivityTestRule.isSplashScreenVisible());
 
         ThreadUtils.runOnUiThread(new Runnable() {
@@ -172,9 +164,8 @@
     @Test
     @SmallTest
     @Feature({"Webapps"})
-    @RetryOnFailure
     public void testHidesAfterMultipleEvents() throws Exception {
-        mActivityTestRule.startWebappActivity();
+        mActivityTestRule.startWebappActivityAndWaitForSplashScreen();
         Assert.assertTrue(mActivityTestRule.isSplashScreenVisible());
 
         ThreadUtils.runOnUiThread(new Runnable() {
@@ -194,9 +185,8 @@
     @Test
     @SmallTest
     @Feature({"Webapps"})
-    @RetryOnFailure
     public void testUmaOnNativeLoad() throws Exception {
-        mActivityTestRule.startWebappActivity();
+        mActivityTestRule.startWebappActivityAndWaitForSplashScreen();
 
         // Tests UMA values.
         Assert.assertEquals(1,
@@ -237,9 +227,8 @@
     @Test
     @SmallTest
     @Feature({"Webapps"})
-    @RetryOnFailure
     public void testUmaWhenSplashHides() throws Exception {
-        mActivityTestRule.startWebappActivity();
+        mActivityTestRule.startWebappActivityAndWaitForSplashScreen();
         ThreadUtils.runOnUiThread(new Runnable() {
             @Override
             public void run() {
@@ -251,7 +240,7 @@
         mActivityTestRule.waitUntilSplashscreenHides();
 
         // DURATION and HIDES should now have a value.
-        Assert.assertTrue(hasHistogramEntry(WebappUma.HISTOGRAM_SPLASHSCREEN_DURATION, 5000));
+        Assert.assertTrue(hasHistogramEntry(WebappUma.HISTOGRAM_SPLASHSCREEN_DURATION, 10000));
         Assert.assertEquals(1,
                 getHistogramTotalCountFor(WebappUma.HISTOGRAM_SPLASHSCREEN_HIDES,
                         WebappUma.SPLASHSCREEN_HIDES_REASON_MAX));
@@ -273,7 +262,6 @@
     @Test
     @SmallTest
     @Feature({"Webapps"})
-    @RetryOnFailure
     public void testRegularSplashScreenAppears() throws Exception {
         // Register a properly-sized icon for the splash screen.
         Context context = mActivityTestRule.getInstrumentation().getTargetContext();
@@ -288,8 +276,7 @@
         callback.waitForCallback(0);
         callback.getStorage().updateSplashScreenImage(bitmapString);
 
-        mActivityTestRule.startWebappActivity();
-        ViewGroup splashScreen = mActivityTestRule.waitUntilSplashScreenAppears();
+        ViewGroup splashScreen = mActivityTestRule.startWebappActivityAndWaitForSplashScreen();
         Assert.assertTrue(mActivityTestRule.isSplashScreenVisible());
 
         ImageView splashImage =
@@ -306,7 +293,6 @@
     @Test
     @SmallTest
     @Feature({"Webapps"})
-    @RetryOnFailure
     public void testSmallSplashScreenAppears() throws Exception {
         // Register a smaller icon for the splash screen.
         Context context = mActivityTestRule.getInstrumentation().getTargetContext();
@@ -322,8 +308,7 @@
         callback.waitForCallback(0);
         callback.getStorage().updateSplashScreenImage(bitmapString);
 
-        mActivityTestRule.startWebappActivity();
-        ViewGroup splashScreen = mActivityTestRule.waitUntilSplashScreenAppears();
+        ViewGroup splashScreen = mActivityTestRule.startWebappActivityAndWaitForSplashScreen();
         Assert.assertTrue(mActivityTestRule.isSplashScreenVisible());
 
         // The icon is centered within a fixed-size area on the splash screen.
@@ -342,7 +327,6 @@
     @Test
     @SmallTest
     @Feature({"Webapps"})
-    @RetryOnFailure
     public void testSplashScreenWithoutImageAppears() throws Exception {
         // Register an image that's too small for the splash screen.
         Context context = mActivityTestRule.getInstrumentation().getTargetContext();
@@ -356,9 +340,9 @@
         callback.waitForCallback(0);
         callback.getStorage().updateSplashScreenImage(bitmapString);
 
-        mActivityTestRule.startWebappActivity(mActivityTestRule.createIntent().putExtra(
-                ShortcutHelper.EXTRA_IS_ICON_GENERATED, true));
-        ViewGroup splashScreen = mActivityTestRule.waitUntilSplashScreenAppears();
+        ViewGroup splashScreen = mActivityTestRule.startWebappActivityAndWaitForSplashScreen(
+                mActivityTestRule.createIntent().putExtra(
+                        ShortcutHelper.EXTRA_IS_ICON_GENERATED, true));
         Assert.assertTrue(mActivityTestRule.isSplashScreenVisible());
 
         // There's no icon displayed.
@@ -380,12 +364,10 @@
     @Test
     @SmallTest
     @Feature({"Webapps"})
-    @RetryOnFailure
     public void testSplashScreenAppearsWithoutRegisteredSplashImage() throws Exception {
         // Don't register anything for the web app, which represents apps that were added to the
         // home screen before splash screen images were downloaded.
-        mActivityTestRule.startWebappActivity();
-        ViewGroup splashScreen = mActivityTestRule.waitUntilSplashScreenAppears();
+        ViewGroup splashScreen = mActivityTestRule.startWebappActivityAndWaitForSplashScreen();
         Assert.assertTrue(mActivityTestRule.isSplashScreenVisible());
 
         // There's no icon displayed.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenThemeColorTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenThemeColorTest.java
index ae36513b..6336c05 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenThemeColorTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenThemeColorTest.java
@@ -19,7 +19,6 @@
 import org.chromium.base.metrics.RecordHistogram;
 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.ChromeSwitches;
 import org.chromium.chrome.browser.ShortcutHelper;
 import org.chromium.chrome.browser.metrics.WebappUma;
@@ -44,9 +43,9 @@
 
     @Before
     public void setUp() throws Exception {
-        mActivityTestRule.startWebappActivity(
-                mActivityTestRule.createIntent()
-                        .putExtra(ShortcutHelper.EXTRA_URL, "http://localhost")
+        mActivityTestRule.startWebappActivityAndWaitForSplashScreen(
+                mActivityTestRule
+                        .createIntent()
                         // This is setting Color.Magenta with 50% opacity.
                         .putExtra(ShortcutHelper.EXTRA_THEME_COLOR, 0x80FF00FFL));
     }
@@ -66,7 +65,6 @@
     @SmallTest
     @Feature({"Webapps"})
     @TargetApi(Build.VERSION_CODES.LOLLIPOP)
-    @RetryOnFailure
     public void testThemeColorNotUsedIfPagesHasOne() {
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return;
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java
index a059324..5e93f92 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java
@@ -94,7 +94,8 @@
         @Features.Register(value = ChromeFeatureList.CHROME_HOME, enabled = false),
         @Features.Register(value = ChromeFeatureList.CHROME_HOME_MODERN_LAYOUT, enabled = false),
         @Features.Register(value = ChromeFeatureList.CONTENT_SUGGESTIONS_SCROLL_TO_LOAD,
-                enabled = false)})
+                enabled = false),
+        @Features.Register(value = ChromeFeatureList.ANDROID_SIGNIN_PROMOS, enabled = false)})
 public class NewTabPageAdapterTest {
     @Rule
     public DisableHistogramsRule mDisableHistogramsRule = new DisableHistogramsRule();
@@ -272,7 +273,8 @@
         CardsVariationParameters.setTestVariationParams(new HashMap<String, String>());
 
         // Initialise the sign in state. We will be signed in by default in the tests.
-        assertFalse(ChromePreferenceManager.getInstance().getNewTabPageSigninPromoDismissed());
+        assertFalse(
+                ChromePreferenceManager.getInstance().getNewTabPageGenericSigninPromoDismissed());
         SigninManager.setInstanceForTesting(mMockSigninManager);
         when(mMockSigninManager.isSignedInOnNative()).thenReturn(true);
         when(mMockSigninManager.isSignInAllowed()).thenReturn(true);
@@ -290,7 +292,7 @@
     public void tearDown() {
         CardsVariationParameters.setTestVariationParams(null);
         SigninManager.setInstanceForTesting(null);
-        ChromePreferenceManager.getInstance().setNewTabPageSigninPromoDismissed(false);
+        ChromePreferenceManager.getInstance().setNewTabPageGenericSigninPromoDismissed(false);
     }
 
     /**
@@ -965,7 +967,8 @@
             @Features.Register(value = ChromeFeatureList.CHROME_HOME),
             @Features.Register(value = ChromeFeatureList.CHROME_HOME_MODERN_LAYOUT),
             @Features.Register(value = ChromeFeatureList.CONTENT_SUGGESTIONS_SCROLL_TO_LOAD,
-                    enabled = false)})
+                enabled = false),
+            @Features.Register(value = ChromeFeatureList.ANDROID_SIGNIN_PROMOS, enabled = false)})
     public void testSigninPromoModern() {
         when(mMockSigninManager.isSignInAllowed()).thenReturn(true);
         when(mMockSigninManager.isSignedInOnNative()).thenReturn(false);
@@ -986,7 +989,7 @@
 
         when(mMockSigninManager.isSignInAllowed()).thenReturn(true);
         when(mMockSigninManager.isSignedInOnNative()).thenReturn(false);
-        ChromePreferenceManager.getInstance().setNewTabPageSigninPromoDismissed(false);
+        ChromePreferenceManager.getInstance().setNewTabPageGenericSigninPromoDismissed(false);
         reloadNtp();
 
         final int signInPromoPosition = mAdapter.getFirstPositionForType(ItemViewType.PROMO);
@@ -997,7 +1000,8 @@
 
         verify(itemDismissedCallback).onResult(anyString());
         assertFalse(isSignInPromoVisible());
-        assertTrue(ChromePreferenceManager.getInstance().getNewTabPageSigninPromoDismissed());
+        assertTrue(
+                ChromePreferenceManager.getInstance().getNewTabPageGenericSigninPromoDismissed());
 
         reloadNtp();
         assertFalse(isSignInPromoVisible());
@@ -1136,7 +1140,8 @@
             @Features.Register(value = ChromeFeatureList.CHROME_HOME),
             @Features.Register(value = ChromeFeatureList.CHROME_HOME_MODERN_LAYOUT),
             @Features.Register(value = ChromeFeatureList.CONTENT_SUGGESTIONS_SCROLL_TO_LOAD,
-                    enabled = false)})
+                enabled = false),
+            @Features.Register(value = ChromeFeatureList.ANDROID_SIGNIN_PROMOS, enabled = false)})
     public void testAllDismissedModern() {
         when(mUiDelegate.isVisible()).thenReturn(true);
 
diff --git a/chrome/app/bookmarks_strings.grdp b/chrome/app/bookmarks_strings.grdp
index 08bcc7a5..465b2c2 100644
--- a/chrome/app/bookmarks_strings.grdp
+++ b/chrome/app/bookmarks_strings.grdp
@@ -386,8 +386,11 @@
   <message name="IDS_MD_BOOKMARK_MANAGER_EMPTY_LIST" desc="The message shown when the user has no bookmarks added. 'Star' refers to the icon in the omnibox for adding to bookmarks.">
     To bookmark pages, click the star in the address bar
   </message>
+  <message name="IDS_MD_BOOKMARK_MANAGER_FOLDER_LABEL" desc="Label for a folder of bookmarks which is used to label folders for screen reader users.">
+    Folder
+  </message>
   <message name="IDS_MD_BOOKMARK_MANAGER_FOLDER_RENAME_TITLE" desc="Title of the bookmark editor window when editing folders.">
-    Rename Folder
+    Rename folder
   </message>
   <message name="IDS_MD_BOOKMARK_MANAGER_MENU_ADD_BOOKMARK" desc="Title of the bookmark toolbar dropdown menu item that adds a new bookmark.">
     Add new bookmark
@@ -429,10 +432,10 @@
     Show in folder
   </message>
   <message name="IDS_MD_BOOKMARK_MANAGER_MENU_SORT" desc="Title of the bookmark toolbar dropdown menu item that sorts bookmarks by title.">
-    Sort by title
+    Sort by name
   </message>
   <message name="IDS_MD_BOOKMARK_MANAGER_MORE_ACTIONS" desc="Tooltip of the button in the bookmark manager which shows an action menu for a bookmark, with actions like 'Edit' or 'Delete'">
-    More actions...
+    More actions
   </message>
   <message name="IDS_MD_BOOKMARK_MANAGER_NO_SEARCH_RESULTS" desc="Text on the bookmarks list that indicates that no bookmarks or folders match the search.">
     No search results found
@@ -456,7 +459,7 @@
     Folder sorted
   </message>
   <message name="IDS_MD_BOOKMARK_MANAGER_TOAST_ITEM_DELETED" desc="Label displayed in toast popup message when a single item is deleted.">
-    '<ph name="DELETED_ITEM_NAME">$1<ex>Bookmark X</ex></ph>' has been deleted
+    '<ph name="DELETED_ITEM_NAME">$1<ex>Bookmark X</ex></ph>' deleted
   </message>
   <message name="IDS_MD_BOOKMARK_MANAGER_TOAST_ITEMS_DELETED" desc="Label displayed in toast popup message when two or more items are deleted.">
     {COUNT, plural,
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 9347cc4..08f22b5 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -5052,25 +5052,25 @@
     Cancel
   </message>
   <message name="IDS_ARC_SIGN_IN_NETWORK_ERROR" desc="Android sign-in error because of network error">
-    Network error
+    Network connection was lost. Please check your connection or try another Wi-Fi network.
   </message>
   <message name="IDS_ARC_SIGN_IN_SERVICE_UNAVAILABLE_ERROR" desc="Android sign-in error because of service is unavailable">
-    Couldn't reach Google Play. Try again now.
+    Couldn't reach Google Play
   </message>
   <message name="IDS_ARC_SIGN_IN_BAD_AUTHENTICATION_ERROR" desc="Android sign-in error because of bad authentification">
-    Bad authentication
+    Couldn’t verify your account. Please try again or restart your Chromebook.
   </message>
   <message name="IDS_ARC_SIGN_IN_GMS_NOT_AVAILABLE_ERROR" desc="Android sign-in error because of GMS services are unavailable">
-    GMS services are unavailable
+    Couldn’t connect with Google services
   </message>
   <message name="IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_FAIL_ERROR" desc="Android sign-in error because of cloud provision flow failed">
-    Cloud provision flow failed
+    Provisioning flow was interrupted. Please try again or contact your device owner or administrator.
   </message>
   <message name="IDS_ARC_SIGN_IN_UNKNOWN_ERROR" desc="Android sign-in error because of unknown error">
-    Unknown error
+    Something went wrong
   </message>
   <message name="IDS_ARC_SERVER_COMMUNICATION_ERROR" desc="Android sign-in error because of server communication error">
-    Server communication error
+    Couldn’t connect with the server. Please check your network connection and try again. If the problem persists, restart your Chromebook.
   </message>
   <message name="IDS_ARC_ANDROID_MANAGEMENT_REQUIRED_ERROR" desc="Error message shown when Android management is required for an unmanaged Chrome OS user.">
     Your organization has not enabled Google Play Store for your account. Contact your administrator for more information.
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index a3ee36c..97b7325 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -5424,6 +5424,18 @@
         Reset to default zoom level
       </message>
 
+      <!-- Accessibility permission -->
+      <message name="IDS_ACCESSIBILITY_EVENTS_PERMISSION_FRAGMENT" desc="Permission request shown if the user is visiting a site that wants to respond to accessibility events, for example if the user is using a screen reader and the site has custom accessibility features. Follows a prompt: 'This site would like to:'">
+        Respond to Accessibility Events
+      </message>
+      <if expr="is_android">
+        <message name="IDS_ACCESSIBILITY_EVENTS_INFOBAR_QUESTION" desc="Question asked on the info bar whenever URL wants to listen to accessibility events, for example if the user has a screen reader or braille device enabled">
+          <ph name="URL">
+            $1<ex>maps.google.com</ex>
+          </ph> wants to respond to accessibility events.
+        </message>
+      </if>
+
       <!-- Feature Engagement Tracker strings -->
       <message name="IDS_BOOKMARK_PROMO_0" desc="Text shown on promotional UI appearing next to the Bookmarks button, which encourages users to use it.">
         Bookmark this page to easily find it later
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index 1c870f2..f664e72a 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -2400,9 +2400,12 @@
   <message name="IDS_SETTINGS_SITE_SETTINGS_DELETE" desc="Label for the trashcan icon used to delete storage on the Site Details page.">
     Delete
   </message>
-  <message name="IDS_SETTINGS_SITE_SETTINGS_COOKIE_HEADER" desc="A header for the list of showing all sites and their data.">
+  <message name="IDS_SETTINGS_SITE_SETTINGS_COOKIE_HEADER" desc="A header for the list of showing all cookies and site data.">
     All cookies and site data
   </message>
+  <message name="IDS_SETTINGS_SITE_SETTINGS_COOKIE_LINK" desc="Label for link showing all cookies and site data.">
+    See all cookies and site data
+  </message>
   <message name="IDS_SETTINGS_SITE_SETTINGS_COOKIE_REMOVE" desc="Label for the button to delete a single site cookie.">
     Remove
   </message>
diff --git a/chrome/app/vector_icons/BUILD.gn b/chrome/app/vector_icons/BUILD.gn
index 1e4a33d..6d99632 100644
--- a/chrome/app/vector_icons/BUILD.gn
+++ b/chrome/app/vector_icons/BUILD.gn
@@ -120,6 +120,7 @@
   if (is_chromeos) {
     icons += [
       "arc_migrate_encryption_notification.icon",
+      "notification_captive_portal.icon",
       "warning_badge_circle.1x.icon",
       "warning_badge_circle.icon",
     ]
diff --git a/chrome/app/vector_icons/notification_captive_portal.icon b/chrome/app/vector_icons/notification_captive_portal.icon
new file mode 100644
index 0000000..14321ff
--- /dev/null
+++ b/chrome/app/vector_icons/notification_captive_portal.icon
@@ -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.
+
+CANVAS_DIMENSIONS, 36,
+MOVE_TO, 17.99f, 23.8f,
+R_H_LINE_TO, -2.66f,
+R_CUBIC_TO, 0.54f, 1.79f, 1.58f, 3.5f, 2.66f, 4.81f,
+V_LINE_TO, 32,
+CUBIC_TO, 10.36f, 32, 4, 25.63f, 4, 18.01f,
+CUBIC_TO, 4, 10.28f, 10.26f, 4, 17.99f, 4,
+CUBIC_TO, 25.74f, 4, 32, 10.27f, 32, 18.01f,
+R_H_LINE_TO, -2.81f,
+R_CUBIC_TO, -0.03f, -0.87f, -0.11f, -1.36f, -0.34f, -2.35f,
+R_H_LINE_TO, -4.74f,
+R_CUBIC_TO, 0.11f, 1.02f, 0.2f, 1.27f, 0.2f, 2.35f,
+R_CUBIC_TO, 0, 0, -3.18f, 0, -3.18f, 0,
+R_CUBIC_TO, 0, -0.95f, -0.01f, -1.35f, -0.13f, -2.35f,
+H_LINE_TO, 14.73f,
+R_CUBIC_TO, -0.13f, 1.01f, -0.22f, 1.4f, -0.22f, 2.35f,
+R_CUBIC_TO, 0, 0.95f, 0.1f, 1.41f, 0.22f, 2.33f,
+R_H_LINE_TO, 3.26f,
+R_V_LINE_TO, 3.46f,
+CLOSE,
+R_MOVE_TO, -9.68f, -11.63f,
+R_H_LINE_TO, 4.13f,
+R_CUBIC_TO, 0.45f, -1.73f, 1.09f, -3.1f, 1.93f, -4.63f,
+R_CUBIC_TO, -2.58f, 0.87f, -4.72f, 2.34f, -6.07f, 4.63f,
+CLOSE,
+R_MOVE_TO, 15.26f, 0,
+R_H_LINE_TO, 4.13f,
+R_CUBIC_TO, -1.34f, -2.31f, -3.49f, -3.87f, -6.06f, -4.76f,
+R_CUBIC_TO, 0.84f, 1.56f, 1.49f, 3.01f, 1.94f, 4.76f,
+CLOSE,
+R_MOVE_TO, -2.89f, 0,
+R_CUBIC_TO, -0.6f, -2.06f, -1.51f, -3.63f, -2.68f, -5.32f,
+R_CUBIC_TO, -1.16f, 1.68f, -2.07f, 3.26f, -2.65f, 5.32f,
+R_H_LINE_TO, 5.32f,
+CLOSE,
+R_MOVE_TO, -8.24f, 11.64f,
+H_LINE_TO, 8.31f,
+R_CUBIC_TO, 1.35f, 2.32f, 3.62f, 4.21f, 6.19f, 5.1f,
+R_CUBIC_TO, -0.84f, -1.55f, -1.61f, -3.35f, -2.06f, -5.1f,
+CLOSE,
+R_MOVE_TO, -5.28f, -3.47f,
+R_H_LINE_TO, 4.74f,
+R_CUBIC_TO, -0.11f, -0.87f, -0.19f, -1.3f, -0.19f, -2.2f,
+R_CUBIC_TO, 0, -0.9f, 0.08f, -1.61f, 0.2f, -2.48f,
+H_LINE_TO, 7.17f,
+R_CUBIC_TO, -0.22f, 0.85f, -0.36f, 1.57f, -0.36f, 2.48f,
+R_CUBIC_TO, 0, 0.91f, 0.14f, 1.36f, 0.36f, 2.2f,
+CLOSE,
+R_MOVE_TO, 19.85f, 10.49f,
+LINE_TO, 23.2f, 27.02f,
+LINE_TO, 20, 30,
+V_LINE_TO, 20,
+R_H_LINE_TO, 10,
+R_LINE_TO, -2.98f, 3.2f,
+R_LINE_TO, 3.82f, 3.82f,
+R_LINE_TO, -3.82f, 3.82f,
+CLOSE,
+END
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 4c670044..bc696173 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -70,6 +70,8 @@
   sources = [
     "about_flags.cc",
     "about_flags.h",
+    "accessibility/accessibility_permission_context.cc",
+    "accessibility/accessibility_permission_context.h",
     "after_startup_task_utils.cc",
     "after_startup_task_utils.h",
     "app_controller_mac.h",
@@ -1796,8 +1798,6 @@
     sources += [
       "crash_upload_list/crash_upload_list_crashpad.cc",
       "crash_upload_list/crash_upload_list_crashpad.h",
-      "media_galleries/fileapi/file_path_watcher_util.cc",
-      "media_galleries/fileapi/file_path_watcher_util.h",
       "media_galleries/fileapi/iapps_data_provider.cc",
       "media_galleries/fileapi/iapps_data_provider.h",
       "media_galleries/fileapi/itunes_data_provider.cc",
@@ -2667,8 +2667,6 @@
       "after_startup_task_utils_android.cc",
       "android/accessibility/font_size_prefs_android.cc",
       "android/accessibility/font_size_prefs_android.h",
-      "android/activity_type_ids.cc",
-      "android/activity_type_ids.h",
       "android/android_theme_resources.h",
       "android/app_hooks.cc",
       "android/app_hooks.h",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index aa9efd34..3bb61c5 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -3415,6 +3415,12 @@
      FEATURE_VALUE_TYPE(features::kSoundContentSetting)},
 #endif  // !defined(OS_ANDROID)
 
+#if DCHECK_IS_ON() && defined(SYZYASAN)
+    {"dcheck-is-fatal", flag_descriptions::kSyzyAsanDcheckIsFatalName,
+     flag_descriptions::kSyzyAsanDcheckIsFatalDescription, kOsWin,
+     FEATURE_VALUE_TYPE(base::kSyzyAsanDCheckIsFatalFeature)},
+#endif  // DCHECK_IS_ON() && defined(SYZYASAN)
+
     // 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/accessibility/accessibility_permission_context.cc b/chrome/browser/accessibility/accessibility_permission_context.cc
new file mode 100644
index 0000000..b62f2622
--- /dev/null
+++ b/chrome/browser/accessibility/accessibility_permission_context.cc
@@ -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.
+
+#include "chrome/browser/accessibility/accessibility_permission_context.h"
+
+AccessibilityPermissionContext::AccessibilityPermissionContext(Profile* profile)
+    : PermissionContextBase(
+          profile,
+          CONTENT_SETTINGS_TYPE_ACCESSIBILITY_EVENTS,
+          blink::WebFeaturePolicyFeature::kAccessibilityEvents) {}
+
+AccessibilityPermissionContext::~AccessibilityPermissionContext() = default;
+
+bool AccessibilityPermissionContext::IsRestrictedToSecureOrigins() const {
+  return false;
+}
diff --git a/chrome/browser/accessibility/accessibility_permission_context.h b/chrome/browser/accessibility/accessibility_permission_context.h
new file mode 100644
index 0000000..c22e5bd
--- /dev/null
+++ b/chrome/browser/accessibility/accessibility_permission_context.h
@@ -0,0 +1,23 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ACCESSIBILITY_ACCESSIBILITY_PERMISSION_CONTEXT_H_
+#define CHROME_BROWSER_ACCESSIBILITY_ACCESSIBILITY_PERMISSION_CONTEXT_H_
+
+#include "base/macros.h"
+#include "chrome/browser/permissions/permission_context_base.h"
+
+class AccessibilityPermissionContext : public PermissionContextBase {
+ public:
+  explicit AccessibilityPermissionContext(Profile* profile);
+  ~AccessibilityPermissionContext() override;
+
+ private:
+  // PermissionContextBase:
+  bool IsRestrictedToSecureOrigins() const override;
+
+  DISALLOW_COPY_AND_ASSIGN(AccessibilityPermissionContext);
+};
+
+#endif  // CHROME_BROWSER_ACCESSIBILITY_ACCESSIBILITY_PERMISSION_CONTEXT_H_
diff --git a/chrome/browser/android/activity_type_ids.cc b/chrome/browser/android/activity_type_ids.cc
deleted file mode 100644
index 98a1724..0000000
--- a/chrome/browser/android/activity_type_ids.cc
+++ /dev/null
@@ -1,19 +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 "chrome/browser/android/activity_type_ids.h"
-
-#include "base/logging.h"
-
-namespace ActivityTypeIds {
-
-Type GetActivityType(int type_id) {
-  if (type_id >= ACTIVITY_NONE && type_id <= ACTIVITY_MAX_VALUE)
-    return Type(type_id);
-
-  NOTREACHED() << "Unhandled Activity id was passed in: " << type_id;
-  return ACTIVITY_MAX_VALUE;
-}
-
-}  // namespace ActivityTypeIds
diff --git a/chrome/browser/android/activity_type_ids.h b/chrome/browser/android/activity_type_ids.h
deleted file mode 100644
index eb478db..0000000
--- a/chrome/browser/android/activity_type_ids.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_ANDROID_ACTIVITY_TYPE_IDS_H_
-#define CHROME_BROWSER_ANDROID_ACTIVITY_TYPE_IDS_H_
-
-// This file maps Activities on Chrome to specific flags for identification.
-
-namespace ActivityTypeIds {
-
-// Define Activities we are interested in tracking.  IDs are assigned
-// consecutively, from NONE to MAX_VALUE.  Activities that are not explicitly
-// defined are all assigned the UNKNOWN value.  When adding new ones, make sure
-// to append them after current Activities and to update the |AndroidActivityId|
-// enum in |histograms.xml|.
-//
-// A Java counterpart will be generated for this enum.
-// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser
-// GENERATED_JAVA_CLASS_NAME_OVERRIDE: ActivityTypeIds
-// GENERATED_JAVA_PREFIX_TO_STRIP: ACTIVITY_
-enum Type {
-  ACTIVITY_NONE = 0,
-  ACTIVITY_UNKNOWN = 1,
-  ACTIVITY_MAIN = 2,
-  ACTIVITY_PREFERENCES = 3,
-  ACTIVITY_WEBAPPACTIVITY = 4,
-  ACTIVITY_FULLSCREENACTIVITY = 5,
-  ACTIVITY_MAX_VALUE = 6
-};
-
-// Takes an int corresponding to a Type and returns the corresponding Type.
-Type GetActivityType(int type_id);
-
-}  // namespace ActivityTypeIds
-
-#endif  // CHROME_BROWSER_ANDROID_ACTIVITY_TYPE_IDS_H_
diff --git a/chrome/browser/android/feature_utilities.cc b/chrome/browser/android/feature_utilities.cc
index b047649..e3dc54d 100644
--- a/chrome/browser/android/feature_utilities.cc
+++ b/chrome/browser/android/feature_utilities.cc
@@ -6,6 +6,8 @@
 
 #include "jni/FeatureUtilities_jni.h"
 
+#include "components/ukm/ukm_source.h"
+
 using base::android::JavaParamRef;
 
 namespace {
@@ -32,6 +34,7 @@
                                 const JavaParamRef<jclass>& clazz,
                                 jboolean visible) {
   custom_tab_visible = visible;
+  ukm::UkmSource::SetCustomTabVisible(visible);
 }
 
 static void SetIsInMultiWindowMode(JNIEnv* env,
diff --git a/chrome/browser/android/locale/locale_manager.cc b/chrome/browser/android/locale/locale_manager.cc
index d2d9ea83..3c9718fe 100644
--- a/chrome/browser/android/locale/locale_manager.cc
+++ b/chrome/browser/android/locale/locale_manager.cc
@@ -20,6 +20,15 @@
 }
 
 // static
+std::string LocaleManager::GetMailRUReferralID() {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  base::android::ScopedJavaLocalRef<jobject> jlocale_manager =
+      Java_LocaleManager_getInstance(env);
+  return base::android::ConvertJavaStringToUTF8(
+      env, Java_LocaleManager_getMailRUReferralId(env, jlocale_manager));
+}
+
+// static
 int GetEngineType(JNIEnv* env,
                   const base::android::JavaParamRef<jclass>& clazz,
                   const base::android::JavaParamRef<jstring>& j_url) {
diff --git a/chrome/browser/android/locale/locale_manager.h b/chrome/browser/android/locale/locale_manager.h
index 792dcf79..34cff2e1 100644
--- a/chrome/browser/android/locale/locale_manager.h
+++ b/chrome/browser/android/locale/locale_manager.h
@@ -14,6 +14,7 @@
 class LocaleManager {
  public:
   static std::string GetYandexReferralID();
+  static std::string GetMailRUReferralID();
 
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(LocaleManager);
diff --git a/chrome/browser/android/resource_id.h b/chrome/browser/android/resource_id.h
index 10614ad..aeab7e7 100644
--- a/chrome/browser/android/resource_id.h
+++ b/chrome/browser/android/resource_id.h
@@ -24,6 +24,8 @@
 LINK_RESOURCE_ID(IDR_BLOCKED_POPUPS, R.drawable.infobar_blocked_popups)
 
 // Android only infobars.
+DECLARE_RESOURCE_ID(IDR_ANDROID_INFOBAR_ACCESSIBILITY_EVENTS,
+                    R.drawable.infobar_accessibility_events)
 DECLARE_RESOURCE_ID(IDR_ANDROID_INFOBAR_FROZEN_TAB, R.drawable.infobar_restore)
 DECLARE_RESOURCE_ID(IDR_ANDROID_INFOBAR_GEOLOCATION,
                     R.drawable.infobar_geolocation)
diff --git a/chrome/browser/android/vr_shell/vr_shell_gl.cc b/chrome/browser/android/vr_shell/vr_shell_gl.cc
index 0914b059..3a1431d 100644
--- a/chrome/browser/android/vr_shell/vr_shell_gl.cc
+++ b/chrome/browser/android/vr_shell/vr_shell_gl.cc
@@ -483,12 +483,17 @@
   browser_->GvrDelegateReady(gvr_api_->GetViewerType());
 }
 
-void VrShellGl::UpdateController(const gfx::Vector3dF& head_direction) {
+void VrShellGl::UpdateController(const gfx::Transform& head_pose) {
+  TRACE_EVENT0("gpu", "VrShellGl::UpdateController");
+  gfx::Vector3dF head_direction = GetForwardVector(head_pose);
+
   controller_->UpdateState(head_direction);
   controller_info_.laser_origin = controller_->GetPointerStart();
 
   device::GvrGamepadData controller_data = controller_->GetGamepadData();
   browser_->UpdateGamepadData(controller_data);
+
+  HandleControllerInput(head_direction);
 }
 
 void VrShellGl::HandleControllerInput(const gfx::Vector3dF& head_direction) {
@@ -809,7 +814,7 @@
   TRACE_EVENT_BEGIN0("gpu", "VrShellGl::AcquireFrame");
   gvr::Frame frame = swap_chain_->AcquireFrame();
   TRACE_EVENT_END0("gpu", "VrShellGl::AcquireFrame");
-  if (!frame.is_valid()) {
+  if (!frame) {
     return;
   }
   frame.BindBuffer(kFramePrimaryBuffer);
@@ -838,15 +843,9 @@
   scene_->OnBeginFrame(current_time,
                        GetForwardVector(render_info_primary_.head_pose));
 
-  {
-    // TODO(crbug.com/704690): Acquire controller state in a way that's timely
-    // for both the gamepad API and UI input handling.
-    TRACE_EVENT0("gpu", "VrShellGl::UpdateController");
-    gfx::Vector3dF head_direction =
-        GetForwardVector(render_info_primary_.head_pose);
-    UpdateController(head_direction);
-    HandleControllerInput(head_direction);
-  }
+  // WebVR handles controller input in OnVsync.
+  if (!ShouldDrawWebVr())
+    UpdateController(render_info_primary_.head_pose);
 
   // Ensure that all elements are ready before drawing. Eg., elements may have
   // been dirtied due to animation on input processing and need to regenerate
@@ -1111,7 +1110,15 @@
     pending_vsync_ = true;
     pending_time_ = frame_time;
   }
-  if (!ShouldDrawWebVr()) {
+  if (ShouldDrawWebVr()) {
+    // When drawing WebVR, controller input doesn't need to be synchronized with
+    // rendering as WebVR uses the gamepad api. To ensure we always handle input
+    // like app button presses, update the controller here, but not in
+    // DrawFrame.
+    gfx::Transform head_pose;
+    device::GvrDelegate::GetGvrPoseWithNeckModel(gvr_api_.get(), &head_pose);
+    UpdateController(render_info_primary_.head_pose);
+  } else {
     DrawFrame(-1);
   }
 }
diff --git a/chrome/browser/android/vr_shell/vr_shell_gl.h b/chrome/browser/android/vr_shell/vr_shell_gl.h
index 2c42e99..0d6fd66 100644
--- a/chrome/browser/android/vr_shell/vr_shell_gl.h
+++ b/chrome/browser/android/vr_shell/vr_shell_gl.h
@@ -127,7 +127,7 @@
   void DrawWebVr();
   bool WebVrPoseByteIsValid(int pose_index_byte);
 
-  void UpdateController(const gfx::Vector3dF& head_direction);
+  void UpdateController(const gfx::Transform& head_pose);
   void HandleWebVrCompatibilityClick();
   std::unique_ptr<blink::WebMouseEvent> MakeMouseEvent(
       blink::WebInputEvent::Type type,
diff --git a/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc b/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc
index 4b45324f6..052c2ff 100644
--- a/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc
+++ b/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc
@@ -879,6 +879,64 @@
   TestHelper("testBlurEvent", "web_view/focus", NO_TEST_SERVER);
 }
 
+// Tests that a <webview> can't steal focus from the embedder.
+IN_PROC_BROWSER_TEST_P(WebViewFocusInteractiveTest,
+                       FrameInGuestWontStealFocus) {
+  // This test only works with OOPIF-based guests, since BrowserPlugin guests
+  // don't keep the WebContentsTree.
+  if (!base::FeatureList::IsEnabled(::features::kGuestViewCrossProcessFrames))
+    return;
+
+  LoadAndLaunchPlatformApp("web_view/simple", "WebViewTest.LAUNCHED");
+
+  content::WebContents* embedder_web_contents = GetFirstAppWindowWebContents();
+  content::WebContents* guest_web_contents =
+      GetGuestViewManager()->WaitForSingleGuestCreated();
+
+  content::MainThreadFrameObserver embedder_observer(
+      embedder_web_contents->GetMainFrame()->GetView()->GetRenderWidgetHost());
+  content::MainThreadFrameObserver guest_observer(
+      guest_web_contents->GetMainFrame()->GetView()->GetRenderWidgetHost());
+
+  // Embedder should be focused initially.
+  EXPECT_EQ(content::GetFocusedWebContents(guest_web_contents),
+            embedder_web_contents);
+
+  // Try to focus an iframe in the guest.
+  EXPECT_TRUE(content::ExecuteScript(
+      guest_web_contents,
+      "document.body.appendChild(document.createElement('iframe')); "
+      "document.querySelector('iframe').focus()"));
+  embedder_observer.Wait();
+  guest_observer.Wait();
+
+  // Embedder should still be focused.
+  EXPECT_EQ(content::GetFocusedWebContents(guest_web_contents),
+            embedder_web_contents);
+
+  // Try to focus the guest from the embedder.
+  EXPECT_TRUE(content::ExecuteScript(
+      embedder_web_contents, "document.querySelector('webview').focus()"));
+  embedder_observer.Wait();
+  guest_observer.Wait();
+
+  // Guest should be focused.
+  EXPECT_EQ(content::GetFocusedWebContents(guest_web_contents),
+            guest_web_contents);
+
+  // Try to focus an iframe in the embedder.
+  EXPECT_TRUE(content::ExecuteScript(
+      embedder_web_contents,
+      "document.body.appendChild(document.createElement('iframe')); "
+      "document.querySelector('iframe').focus()"));
+  embedder_observer.Wait();
+  guest_observer.Wait();
+
+  // Embedder is allowed to steal focus from guest.
+  EXPECT_EQ(content::GetFocusedWebContents(guest_web_contents),
+            embedder_web_contents);
+}
+
 // Tests that guests receive edit commands and respond appropriately.
 IN_PROC_BROWSER_TEST_P(WebViewInteractiveTest, EditCommands) {
   LoadAndLaunchPlatformApp("web_view/edit_commands", "connected");
diff --git a/chrome/browser/autocomplete/autocomplete_classifier_factory.cc b/chrome/browser/autocomplete/autocomplete_classifier_factory.cc
index 9e8de32..546f574 100644
--- a/chrome/browser/autocomplete/autocomplete_classifier_factory.cc
+++ b/chrome/browser/autocomplete/autocomplete_classifier_factory.cc
@@ -7,6 +7,7 @@
 #include "base/memory/ptr_util.h"
 #include "chrome/browser/autocomplete/chrome_autocomplete_provider_client.h"
 #include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h"
+#include "chrome/browser/autocomplete/contextual_suggestions_service_factory.h"
 #include "chrome/browser/autocomplete/in_memory_url_index_factory.h"
 #include "chrome/browser/autocomplete/shortcuts_backend_factory.h"
 #include "chrome/browser/profiles/incognito_helpers.h"
@@ -59,6 +60,7 @@
   //   DependsOn(PrefServiceFactory::GetInstance());
   DependsOn(ShortcutsBackendFactory::GetInstance());
   DependsOn(InMemoryURLIndexFactory::GetInstance());
+  DependsOn(ContextualSuggestionsServiceFactory::GetInstance());
 }
 
 AutocompleteClassifierFactory::~AutocompleteClassifierFactory() {
diff --git a/chrome/browser/chrome_content_browser_manifest_overlay.json b/chrome/browser/chrome_content_browser_manifest_overlay.json
index 7301147..bb01c75 100644
--- a/chrome/browser/chrome_content_browser_manifest_overlay.json
+++ b/chrome/browser/chrome_content_browser_manifest_overlay.json
@@ -40,6 +40,8 @@
         "content_browser": [ "memlog_client" ],
         "device": [ "device:fingerprint" ],
         "identity": [ "identity_manager" ],
+        // Only used in classic ash case.
+        "local_state": [ "pref_client" ],
         "nacl_broker": [ "browser" ],
         "nacl_loader": [ "browser" ],
         "profiling": [ "memlog" ],
diff --git a/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_arc_home_service.cc b/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_arc_home_service.cc
index b9687301..e4ea8683 100644
--- a/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_arc_home_service.cc
+++ b/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_arc_home_service.cc
@@ -23,6 +23,7 @@
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/pref_names.h"
 #include "chromeos/chromeos_switches.h"
 #include "components/arc/arc_bridge_service.h"
 #include "components/arc/arc_browser_context_keyed_service_factory_base.h"
@@ -265,9 +266,12 @@
     const GetVoiceInteractionStructureCallback& callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
+  PrefService* prefs = Profile::FromBrowserContext(context_)->GetPrefs();
   auto* framework_service =
       ArcVoiceInteractionFrameworkService::GetForBrowserContext(context_);
-  if (!framework_service->ValidateTimeSinceUserInteraction()) {
+  if (!framework_service->ValidateTimeSinceUserInteraction() ||
+      !prefs->GetBoolean(prefs::kVoiceInteractionEnabled) ||
+      !prefs->GetBoolean(prefs::kVoiceInteractionContextEnabled)) {
     callback.Run(mojom::VoiceInteractionStructure::New());
     return;
   }
@@ -303,11 +307,6 @@
   VLOG(1) << "Assistant wizard is completed.";
   UnlockPai();
   chromeos::first_run::MaybeLaunchDialogImmediately();
-  arc::ArcVoiceInteractionFrameworkService* framework_service =
-      arc::ArcVoiceInteractionFrameworkService::GetForBrowserContext(context_);
-  if (!framework_service)
-    return;  // Happens in unit tests.
-  framework_service->UpdateVoiceInteractionPrefs();
 }
 
 // static
diff --git a/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.cc b/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.cc
index 8519f65c..9bf29554 100644
--- a/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.cc
+++ b/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.cc
@@ -300,9 +300,31 @@
   // Android side so we don't need to synchronize it here.
   if (state_ == ash::VoiceInteractionState::NOT_READY) {
     PrefService* prefs = Profile::FromBrowserContext(context_)->GetPrefs();
+    bool value_prop_accepted =
+        prefs->GetBoolean(prefs::kArcVoiceInteractionValuePropAccepted);
+
+    // Currerntly we are doing this so that we don't break existing users. Users
+    // before prefs::kVoiceInteractionEnabled and
+    // prefs::kVoiceInteractionContextEnabled are introduced will have default
+    // |false| value. To avoid breaking existing users, if they have already
+    // accepted value prop (prefs::kArcVoiceInteractionValuePropAccepted ==
+    // true), but prefs::kVoiceInteractionEnabled and
+    // prefs::kVoiceInteractionContextEnabled are not set, we set them to true.
+    // prefs::kArcVoiceInteractionValuePropAccepted == true, but
+    // prefs::kVoiceInteractionEnabled and
+    // prefs::kVoiceInteractionContextEnabled are not set, is an invalid state.
+    // TODO(muyuanli): Remove checking whether |voice_interaction_enabled| is
+    // undefined in the future.
+    bool enable_voice_interaction =
+        value_prop_accepted &&
+        (!prefs->GetUserPrefValue(prefs::kVoiceInteractionEnabled) ||
+         prefs->GetBoolean(prefs::kVoiceInteractionEnabled));
+    SetVoiceInteractionEnabled(enable_voice_interaction);
+
     SetVoiceInteractionContextEnabled(
-        prefs->GetBoolean(prefs::kArcVoiceInteractionValuePropAccepted) &&
-        prefs->GetBoolean(prefs::kVoiceInteractionContextEnabled));
+        (enable_voice_interaction &&
+         (prefs->GetBoolean(prefs::kVoiceInteractionContextEnabled) ||
+          !prefs->GetUserPrefValue(prefs::kVoiceInteractionContextEnabled))));
   }
   state_ = state;
   ash::Shell::Get()->NotifyVoiceInteractionStatusChanged(state);
@@ -334,6 +356,8 @@
     bool enabled) {
   if (enabled)
     return;
+  PrefService* prefs = Profile::FromBrowserContext(context_)->GetPrefs();
+  prefs->SetBoolean(prefs::kArcVoiceInteractionValuePropAccepted, false);
   mojom::VoiceInteractionStatusPtr status =
       mojom::VoiceInteractionStatus::New();
   status->configured = false;
@@ -360,18 +384,31 @@
       prefs::kVoiceInteractionContextEnabled);
   ash::Shell::Get()->NotifyVoiceInteractionContextEnabled(context);
 
+  if (Profile::FromBrowserContext(context_)->GetPrefs()->GetBoolean(
+          prefs::kArcVoiceInteractionValuePropAccepted))
+    ash::Shell::Get()->NotifyVoiceInteractionSetupCompleted();
+
   // We only want notify the status change on first user signed in.
   session_manager::SessionManager::Get()->RemoveObserver(this);
 }
 
 void ArcVoiceInteractionFrameworkService::StartVoiceInteractionSetupWizard() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
   arc::mojom::VoiceInteractionFrameworkInstance* framework_instance =
       ARC_GET_INSTANCE_FOR_METHOD(
           arc_bridge_service_->voice_interaction_framework(),
           StartVoiceInteractionSetupWizard);
+
   if (!framework_instance)
     return;
+
+  if (should_start_runtime_flow_) {
+    VLOG(1) << "Starting runtime setup flow.";
+    framework_instance->StartVoiceInteractionSession();
+    return;
+  }
+
   framework_instance->StartVoiceInteractionSetupWizard();
 }
 
@@ -410,6 +447,8 @@
   // all possible entry points on CrOS side with this flag. In this case,
   // we only need to set CrOS side flag.
   prefs->SetBoolean(prefs::kVoiceInteractionEnabled, enable);
+  if (!enable)
+    prefs->SetBoolean(prefs::kVoiceInteractionContextEnabled, false);
 }
 
 void ArcVoiceInteractionFrameworkService::SetVoiceInteractionContextEnabled(
@@ -445,6 +484,17 @@
       base::Bind(&SetVoiceInteractionPrefs, context_));
 }
 
+void ArcVoiceInteractionFrameworkService::SetVoiceInteractionSetupCompleted() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  PrefService* prefs = Profile::FromBrowserContext(context_)->GetPrefs();
+  prefs->SetBoolean(prefs::kArcVoiceInteractionValuePropAccepted, true);
+  prefs->SetBoolean(prefs::kVoiceInteractionEnabled, true);
+  prefs->SetBoolean(prefs::kVoiceInteractionContextEnabled, true);
+
+  ash::Shell::Get()->NotifyVoiceInteractionSetupCompleted();
+}
+
 void ArcVoiceInteractionFrameworkService::StartSessionFromUserInteraction(
     const gfx::Rect& rect) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -516,8 +566,8 @@
 
 bool ArcVoiceInteractionFrameworkService::InitiateUserInteraction() {
   VLOG(1) << "Start voice interaction.";
-  if (!Profile::FromBrowserContext(context_)->GetPrefs()->GetBoolean(
-          prefs::kArcVoiceInteractionValuePropAccepted)) {
+  PrefService* prefs = Profile::FromBrowserContext(context_)->GetPrefs();
+  if (!prefs->GetBoolean(prefs::kArcVoiceInteractionValuePropAccepted)) {
     VLOG(1) << "Voice interaction feature not accepted.";
     // If voice interaction value prop already showing, return.
     if (chromeos::LoginDisplayHost::default_host())
@@ -528,10 +578,14 @@
     // The display host will be destructed at the end of OOBE flow.
     chromeos::LoginDisplayHostImpl* display_host =
         new chromeos::LoginDisplayHostImpl(screen_bounds);
+    should_start_runtime_flow_ = true;
     display_host->StartVoiceInteractionOobe();
     return false;
   }
 
+  if (!prefs->GetBoolean(prefs::kVoiceInteractionEnabled))
+    return false;
+
   if (state_ == ash::VoiceInteractionState::NOT_READY) {
     // If the container side is not ready, we will be waiting for a while.
     ash::Shell::Get()->NotifyVoiceInteractionStatusChanged(
diff --git a/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.h b/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.h
index efd2847..7173a34 100644
--- a/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.h
+++ b/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.h
@@ -112,6 +112,9 @@
   // container is enabled.
   void UpdateVoiceInteractionPrefs();
 
+  // Set voice interaction setup completed flag and notify the change.
+  void SetVoiceInteractionSetupCompleted();
+
   // For supporting ArcServiceManager::GetService<T>().
   static const char kArcServiceName[];
 
@@ -127,6 +130,9 @@
   // Whether there is a pending request to start voice interaction.
   bool is_request_pending_ = false;
 
+  // Whether we should launch runtime setup flow for voice interaction.
+  bool should_start_runtime_flow_ = false;
+
   // The current state voice interaction service is. There is usually a long
   // delay after boot before the service is ready. We wait for the container
   // to tell us if it is ready to quickly serve voice interaction requests.
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
index e6c6aac..08505e7 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
@@ -24,6 +24,7 @@
 #include "chrome/browser/chromeos/file_manager/zip_file_creator.h"
 #include "chrome/browser/chromeos/file_system_provider/mount_path_util.h"
 #include "chrome/browser/chromeos/file_system_provider/service.h"
+#include "chrome/browser/chromeos/fileapi/recent_file.h"
 #include "chrome/browser/chromeos/fileapi/recent_model.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
@@ -748,7 +749,7 @@
 
 void FileManagerPrivateInternalGetRecentFilesFunction::OnGetRecentFiles(
     api::file_manager_private::SourceRestriction restriction,
-    const std::vector<storage::FileSystemURL>& urls) {
+    const std::vector<chromeos::RecentFile>& files) {
   scoped_refptr<storage::FileSystemContext> file_system_context =
       file_manager::util::GetFileSystemContextForRenderFrameHost(
           chrome_details_.GetProfile(), render_frame_host());
@@ -759,21 +760,21 @@
   DCHECK(external_backend);
 
   file_manager::util::FileDefinitionList file_definition_list;
-  for (const storage::FileSystemURL& url : urls) {
-    DCHECK(external_backend->CanHandleType(url.type()));
+  for (const auto& file : files) {
+    DCHECK(external_backend->CanHandleType(file.url().type()));
 
     // Filter out files from non-allowed sources.
     // We do this filtering here rather than in RecentModel so that the set of
     // files returned with some restriction is a subset of what would be
     // returned without restriction. Anyway, the maximum number of files
     // returned from RecentModel is large enough.
-    if (!IsAllowedSource(url.type(), restriction))
+    if (!IsAllowedSource(file.url().type(), restriction))
       continue;
 
     file_manager::util::FileDefinition file_definition;
     const bool result =
         file_manager::util::ConvertAbsoluteFilePathToRelativeFileSystemPath(
-            chrome_details_.GetProfile(), extension_id(), url.path(),
+            chrome_details_.GetProfile(), extension_id(), file.url().path(),
             &file_definition.virtual_path);
     if (!result)
       continue;
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h
index 3e5f423c..0f29ad76 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h
@@ -22,6 +22,10 @@
 #include "google_apis/drive/drive_api_error_codes.h"
 #include "storage/browser/fileapi/file_system_url.h"
 
+namespace chromeos {
+class RecentFile;
+}  // namespace chromeos
+
 namespace file_manager {
 namespace util {
 struct EntryDefinition;
@@ -294,7 +298,7 @@
   ResponseAction Run() override;
   void OnGetRecentFiles(
       api::file_manager_private::SourceRestriction restriction,
-      const std::vector<storage::FileSystemURL>& urls);
+      const std::vector<chromeos::RecentFile>& files);
   void OnConvertFileDefinitionListToEntryDefinitionList(
       std::unique_ptr<file_manager::util::EntryDefinitionList>
           entry_definition_list);
diff --git a/chrome/browser/chromeos/file_manager/file_manager_jstest.cc b/chrome/browser/chromeos/file_manager/file_manager_jstest.cc
index c1bbc20e..c60d80d 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_jstest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_jstest.cc
@@ -198,3 +198,8 @@
   RunTest(base::FilePath(
       FILE_PATH_LITERAL("foreground/js/file_list_model_unittest.html")));
 }
+
+IN_PROC_BROWSER_TEST_F(FileManagerJsTest, FileTapHandler) {
+  RunTest(base::FilePath(
+      FILE_PATH_LITERAL("foreground/js/ui/file_tap_handler_unittest.html")));
+}
diff --git a/chrome/browser/chromeos/fileapi/recent_model.cc b/chrome/browser/chromeos/fileapi/recent_model.cc
index 5876cb80..c11e6a4 100644
--- a/chrome/browser/chromeos/fileapi/recent_model.cc
+++ b/chrome/browser/chromeos/fileapi/recent_model.cc
@@ -80,8 +80,8 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   // Use cache if available.
-  if (cached_urls_.has_value()) {
-    std::move(callback).Run(cached_urls_.value());
+  if (cached_files_.has_value()) {
+    std::move(callback).Run(cached_files_.value());
     return;
   }
 
@@ -150,18 +150,18 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   DCHECK_EQ(0, num_inflight_sources_);
-  DCHECK(!cached_urls_.has_value());
+  DCHECK(!cached_files_.has_value());
   DCHECK(!build_start_time_.is_null());
 
-  std::vector<storage::FileSystemURL> urls;
+  std::vector<RecentFile> files;
   while (!intermediate_files_.empty()) {
-    urls.emplace_back(intermediate_files_.top().url());
+    files.emplace_back(intermediate_files_.top());
     intermediate_files_.pop();
   }
-  std::reverse(urls.begin(), urls.end());
-  cached_urls_ = std::move(urls);
+  std::reverse(files.begin(), files.end());
+  cached_files_ = std::move(files);
 
-  DCHECK(cached_urls_.has_value());
+  DCHECK(cached_files_.has_value());
   DCHECK(intermediate_files_.empty());
 
   UMA_HISTOGRAM_TIMES(kLoadHistogramName,
@@ -179,13 +179,13 @@
   DCHECK(pending_callbacks_.empty());
   DCHECK(!callbacks_to_call.empty());
   for (auto& callback : callbacks_to_call)
-    std::move(callback).Run(cached_urls_.value());
+    std::move(callback).Run(cached_files_.value());
 }
 
 void RecentModel::ClearCache() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  cached_urls_.reset();
+  cached_files_.reset();
 }
 
 void RecentModel::SetMaxFilesForTest(size_t max_files) {
diff --git a/chrome/browser/chromeos/fileapi/recent_model.h b/chrome/browser/chromeos/fileapi/recent_model.h
index 1ece3cf0..a741fb9e 100644
--- a/chrome/browser/chromeos/fileapi/recent_model.h
+++ b/chrome/browser/chromeos/fileapi/recent_model.h
@@ -28,7 +28,6 @@
 namespace storage {
 
 class FileSystemContext;
-class FileSystemURL;
 
 }  // namespace storage
 
@@ -42,7 +41,7 @@
 class RecentModel : public KeyedService {
  public:
   using GetRecentFilesCallback =
-      base::OnceCallback<void(const std::vector<storage::FileSystemURL>& urls)>;
+      base::OnceCallback<void(const std::vector<RecentFile>& files)>;
 
   ~RecentModel() override;
 
@@ -93,8 +92,7 @@
   base::Optional<base::Time> forced_cutoff_time_;
 
   // Cached GetRecentFiles() response.
-  base::Optional<std::vector<storage::FileSystemURL>> cached_urls_ =
-      base::nullopt;
+  base::Optional<std::vector<RecentFile>> cached_files_ = base::nullopt;
 
   // Timer to clear the cache.
   base::OneShotTimer cache_clear_timer_;
diff --git a/chrome/browser/chromeos/fileapi/recent_model_unittest.cc b/chrome/browser/chromeos/fileapi/recent_model_unittest.cc
index 91eaf64..7d61c7f 100644
--- a/chrome/browser/chromeos/fileapi/recent_model_unittest.cc
+++ b/chrome/browser/chromeos/fileapi/recent_model_unittest.cc
@@ -54,7 +54,7 @@
     return sources;
   }
 
-  std::vector<storage::FileSystemURL> BuildModelAndGetRecentFiles(
+  std::vector<RecentFile> BuildModelAndGetRecentFiles(
       std::vector<std::unique_ptr<RecentSource>> sources,
       size_t max_files,
       const base::Time& cutoff_time) {
@@ -64,24 +64,23 @@
     model->SetMaxFilesForTest(max_files);
     model->SetForcedCutoffTimeForTest(cutoff_time);
 
-    std::vector<storage::FileSystemURL> urls;
+    std::vector<RecentFile> files;
 
     base::RunLoop run_loop;
 
     model->GetRecentFiles(
         nullptr /* file_system_context */, GURL() /* origin */,
         base::BindOnce(
-            [](base::RunLoop* run_loop,
-               std::vector<storage::FileSystemURL>* urls_out,
-               const std::vector<storage::FileSystemURL>& urls) {
-              *urls_out = urls;
+            [](base::RunLoop* run_loop, std::vector<RecentFile>* files_out,
+               const std::vector<RecentFile>& files) {
+              *files_out = files;
               run_loop->Quit();
             },
-            &run_loop, &urls));
+            &run_loop, &files));
 
     run_loop.Run();
 
-    return urls;
+    return files;
   }
 
   content::TestBrowserThreadBundle thread_bundle_;
@@ -89,33 +88,42 @@
 };
 
 TEST_F(RecentModelTest, GetRecentFiles) {
-  std::vector<storage::FileSystemURL> urls =
+  std::vector<RecentFile> files =
       BuildModelAndGetRecentFiles(BuildDefaultSources(), 10, base::Time());
 
-  ASSERT_EQ(4u, urls.size());
-  EXPECT_EQ("ddd.jpg", urls[0].path().value());
-  EXPECT_EQ("ccc.jpg", urls[1].path().value());
-  EXPECT_EQ("bbb.jpg", urls[2].path().value());
-  EXPECT_EQ("aaa.jpg", urls[3].path().value());
+  ASSERT_EQ(4u, files.size());
+  EXPECT_EQ("ddd.jpg", files[0].url().path().value());
+  EXPECT_EQ(base::Time::FromJavaTime(4000), files[0].last_modified());
+  EXPECT_EQ("ccc.jpg", files[1].url().path().value());
+  EXPECT_EQ(base::Time::FromJavaTime(3000), files[1].last_modified());
+  EXPECT_EQ("bbb.jpg", files[2].url().path().value());
+  EXPECT_EQ(base::Time::FromJavaTime(2000), files[2].last_modified());
+  EXPECT_EQ("aaa.jpg", files[3].url().path().value());
+  EXPECT_EQ(base::Time::FromJavaTime(1000), files[3].last_modified());
 }
 
 TEST_F(RecentModelTest, GetRecentFiles_MaxFiles) {
-  std::vector<storage::FileSystemURL> urls =
+  std::vector<RecentFile> files =
       BuildModelAndGetRecentFiles(BuildDefaultSources(), 3, base::Time());
 
-  ASSERT_EQ(3u, urls.size());
-  EXPECT_EQ("ddd.jpg", urls[0].path().value());
-  EXPECT_EQ("ccc.jpg", urls[1].path().value());
-  EXPECT_EQ("bbb.jpg", urls[2].path().value());
+  ASSERT_EQ(3u, files.size());
+  EXPECT_EQ("ddd.jpg", files[0].url().path().value());
+  EXPECT_EQ(base::Time::FromJavaTime(4000), files[0].last_modified());
+  EXPECT_EQ("ccc.jpg", files[1].url().path().value());
+  EXPECT_EQ(base::Time::FromJavaTime(3000), files[1].last_modified());
+  EXPECT_EQ("bbb.jpg", files[2].url().path().value());
+  EXPECT_EQ(base::Time::FromJavaTime(2000), files[2].last_modified());
 }
 
 TEST_F(RecentModelTest, GetRecentFiles_CutoffTime) {
-  std::vector<storage::FileSystemURL> urls = BuildModelAndGetRecentFiles(
+  std::vector<RecentFile> files = BuildModelAndGetRecentFiles(
       BuildDefaultSources(), 10, base::Time::FromJavaTime(2500));
 
-  ASSERT_EQ(2u, urls.size());
-  EXPECT_EQ("ddd.jpg", urls[0].path().value());
-  EXPECT_EQ("ccc.jpg", urls[1].path().value());
+  ASSERT_EQ(2u, files.size());
+  EXPECT_EQ("ddd.jpg", files[0].url().path().value());
+  EXPECT_EQ(base::Time::FromJavaTime(4000), files[0].last_modified());
+  EXPECT_EQ("ccc.jpg", files[1].url().path().value());
+  EXPECT_EQ(base::Time::FromJavaTime(3000), files[1].last_modified());
 }
 
 TEST_F(RecentModelTest, GetRecentFiles_UmaStats) {
diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc b/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc
index 1bd121ff3..ecd29cd4 100644
--- a/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc
+++ b/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc
@@ -89,6 +89,7 @@
   }
   void SetImesManagedByPolicy(bool managed) override {}
   void ShowImeMenuOnShelf(bool show) override {}
+  void SetCapsLockState(bool enabled) override {}
 
   std::string current_ime_id_;
   std::vector<ash::mojom::ImeInfoPtr> available_imes_;
diff --git a/chrome/browser/chromeos/login/screens/voice_interaction_value_prop_screen.cc b/chrome/browser/chromeos/login/screens/voice_interaction_value_prop_screen.cc
index 991f5956..d42360b8 100644
--- a/chrome/browser/chromeos/login/screens/voice_interaction_value_prop_screen.cc
+++ b/chrome/browser/chromeos/login/screens/voice_interaction_value_prop_screen.cc
@@ -9,8 +9,6 @@
 #include "chrome/browser/chromeos/login/screens/voice_interaction_value_prop_screen_view.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/common/pref_names.h"
-#include "components/prefs/pref_service.h"
 
 namespace chromeos {
 namespace {
@@ -72,8 +70,6 @@
 
 void VoiceInteractionValuePropScreen::OnNextPressed() {
   GetVoiceInteractionHomeService()->OnAssistantAppRequested();
-  ProfileManager::GetActiveUserProfile()->GetPrefs()->SetBoolean(
-      prefs::kArcVoiceInteractionValuePropAccepted, true);
   Finish(ScreenExitCode::VOICE_INTERACTION_VALUE_PROP_ACCEPTED);
 }
 
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc
index 3a20732..38ad4b2b 100644
--- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc
+++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc
@@ -334,7 +334,8 @@
     started_load_at_ = base::Time::Now();
 
     if (default_) {
-      manager->DoSetDefaultWallpaper(account_id_, std::move(on_finish_));
+      manager->DoSetDefaultWallpaper(account_id_, true /* update_wallpaper */,
+                                     std::move(on_finish_));
     } else if (!user_wallpaper_.isNull()) {
       SetWallpaper(user_wallpaper_, info_);
     } else if (!wallpaper_path_.empty()) {
@@ -347,7 +348,8 @@
                          base::Passed(std::move(on_finish_)),
                          manager->weak_factory_.GetWeakPtr()));
     } else if (!info_.location.empty()) {
-      manager->LoadWallpaper(account_id_, info_, true, std::move(on_finish_));
+      manager->LoadWallpaper(account_id_, info_, true /* update_wallpaper */,
+                             std::move(on_finish_));
     } else {
       // PendingWallpaper was created and never initialized?
       NOTREACHED();
@@ -696,6 +698,7 @@
 
 void WallpaperManager::DoSetDefaultWallpaper(
     const AccountId& account_id,
+    bool update_wallpaper,
     MovableOnDestroyCallbackHolder on_finish) {
   // There is no visible wallpaper in kiosk mode.
   if (user_manager::UserManager::Get()->IsLoggedInAsKioskApp())
@@ -729,21 +732,26 @@
     default_wallpaper_image_.reset();
     if (!file->empty()) {
       loaded_wallpapers_for_test_++;
-      StartLoadAndSetDefaultWallpaper(*file, layout, std::move(on_finish),
+      StartLoadAndSetDefaultWallpaper(*file, layout, update_wallpaper,
+                                      std::move(on_finish),
                                       &default_wallpaper_image_);
       return;
     }
 
     CreateSolidDefaultWallpaper();
   }
-  // 1x1 wallpaper is actually solid color, so it should be stretched.
-  if (default_wallpaper_image_->image().width() == 1 &&
-      default_wallpaper_image_->image().height() == 1)
-    layout = wallpaper::WALLPAPER_LAYOUT_STRETCH;
 
-  WallpaperInfo info(default_wallpaper_image_->file_path().value(), layout,
-                     wallpaper::DEFAULT, base::Time::Now().LocalMidnight());
-  SetWallpaper(default_wallpaper_image_->image(), info);
+  if (update_wallpaper) {
+    // 1x1 wallpaper is actually solid color, so it should be stretched.
+    if (default_wallpaper_image_->image().width() == 1 &&
+        default_wallpaper_image_->image().height() == 1) {
+      layout = wallpaper::WALLPAPER_LAYOUT_STRETCH;
+    }
+
+    WallpaperInfo info(default_wallpaper_image_->file_path().value(), layout,
+                       wallpaper::DEFAULT, base::Time::Now().LocalMidnight());
+    SetWallpaper(default_wallpaper_image_->image(), info);
+  }
 }
 
 void WallpaperManager::SetUserWallpaperInfo(const AccountId& account_id,
@@ -1263,9 +1271,7 @@
         "", wallpaper::WALLPAPER_LAYOUT_CENTER_CROPPED, wallpaper::DEFAULT,
         base::Time::Now().LocalMidnight());
     SetUserWallpaperInfo(account_id, default_info, true);
-
-    if (update_wallpaper)
-      DoSetDefaultWallpaper(account_id, std::move(on_finish));
+    DoSetDefaultWallpaper(account_id, update_wallpaper, std::move(on_finish));
     return;
   }
 
@@ -1404,6 +1410,7 @@
 void WallpaperManager::OnDefaultWallpaperDecoded(
     const base::FilePath& path,
     const wallpaper::WallpaperLayout layout,
+    bool update_wallpaper,
     std::unique_ptr<user_manager::UserImage>* result_out,
     MovableOnDestroyCallbackHolder on_finish,
     std::unique_ptr<user_manager::UserImage> user_image) {
@@ -1413,21 +1420,24 @@
   }
 
   *result_out = std::move(user_image);
-  WallpaperInfo info(path.value(), layout, wallpaper::DEFAULT,
-                     base::Time::Now().LocalMidnight());
-  SetWallpaper((*result_out)->image(), info);
+  if (update_wallpaper) {
+    WallpaperInfo info(path.value(), layout, wallpaper::DEFAULT,
+                       base::Time::Now().LocalMidnight());
+    SetWallpaper((*result_out)->image(), info);
+  }
 }
 
 void WallpaperManager::StartLoadAndSetDefaultWallpaper(
     const base::FilePath& path,
     const wallpaper::WallpaperLayout layout,
+    bool update_wallpaper,
     MovableOnDestroyCallbackHolder on_finish,
     std::unique_ptr<user_manager::UserImage>* result_out) {
   user_image_loader::StartWithFilePath(
       task_runner_, path, ImageDecoder::ROBUST_JPEG_CODEC,
       0,  // Do not crop.
       base::Bind(&WallpaperManager::OnDefaultWallpaperDecoded,
-                 weak_factory_.GetWeakPtr(), path, layout,
+                 weak_factory_.GetWeakPtr(), path, layout, update_wallpaper,
                  base::Unretained(result_out),
                  base::Passed(std::move(on_finish))));
 }
@@ -1469,8 +1479,8 @@
     }
   }
 
-  if (need_update_screen)
-    DoSetDefaultWallpaper(EmptyAccountId(), MovableOnDestroyCallbackHolder());
+  DoSetDefaultWallpaper(EmptyAccountId(), need_update_screen,
+                        MovableOnDestroyCallbackHolder());
 }
 
 void WallpaperManager::RecordWallpaperAppType() {
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h
index 3de3f1e..8715439 100644
--- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h
+++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h
@@ -82,6 +82,7 @@
   void SetDefaultWallpaperDelayed(const AccountId& account_id) override;
   void DoSetDefaultWallpaper(
       const AccountId& account_id,
+      bool update_wallpaper,
       wallpaper::MovableOnDestroyCallbackHolder on_finish) override;
   void SetUserWallpaperInfo(const AccountId& account_id,
                             const wallpaper::WallpaperInfo& info,
@@ -200,12 +201,14 @@
   void OnDefaultWallpaperDecoded(
       const base::FilePath& path,
       const wallpaper::WallpaperLayout layout,
+      bool update_wallpaper,
       std::unique_ptr<user_manager::UserImage>* result,
       wallpaper::MovableOnDestroyCallbackHolder on_finish,
       std::unique_ptr<user_manager::UserImage> user_image) override;
   void StartLoadAndSetDefaultWallpaper(
       const base::FilePath& path,
       const wallpaper::WallpaperLayout layout,
+      bool update_wallpaper,
       wallpaper::MovableOnDestroyCallbackHolder on_finish,
       std::unique_ptr<user_manager::UserImage>* result_out) override;
   void SetDefaultWallpaperPath(
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_browsertest.cc b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_browsertest.cc
index 68f80ca..2e970e5 100644
--- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_browsertest.cc
+++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_browsertest.cc
@@ -851,4 +851,63 @@
   EXPECT_FALSE(WallpaperManager::Get()->IsPendingWallpaper(
       wallpaper::WallpaperResizer::GetImageId(image)));
 }
+
+// Tests that if there are multiple users on the device and if one user lost his
+// wallpaper somehow, the wallpapers should still show correctly on lock/login
+// screen.
+IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest, CustomWallpaperLostTest) {
+  UpdateDisplay("640x480");
+  WallpaperManager* wallpaper_manager = WallpaperManager::Get();
+
+  LogIn(test_account_id1_, kTestUser1Hash);
+  wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished();
+
+  // Now log in |test_account_id2_| to make it the current active user.
+  LogIn(test_account_id2_, kTestUser2Hash);
+  wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished();
+  EXPECT_EQ(user_manager::UserManager::Get()->GetActiveUser()->GetAccountId(),
+            test_account_id2_);
+
+  // Set a different wallpaper for |test_account_id2_|.
+  std::string id = std::to_string(
+      std::abs((base::Time::Now() - base::Time::Now().LocalMidnight())
+                   .InMilliseconds()));
+  base::FilePath small_wallpaper_path = GetCustomWallpaperPath(
+      wallpaper::kSmallWallpaperSubDir, test_account2_wallpaper_files_id_, id);
+  ASSERT_TRUE(wallpaper_manager_test_utils::WriteJPEGFile(
+      small_wallpaper_path, kSmallWallpaperWidth, kSmallWallpaperHeight,
+      wallpaper_manager_test_utils::kCustomWallpaperColor));
+  std::string relative_path2 =
+      base::FilePath(test_account2_wallpaper_files_id_.id()).Append(id).value();
+  WallpaperInfo info2 = {relative_path2, WALLPAPER_LAYOUT_CENTER_CROPPED,
+                         wallpaper::CUSTOMIZED,
+                         base::Time::Now().LocalMidnight()};
+  wallpaper_manager->SetUserWallpaperInfo(test_account_id2_, info2, true);
+  wallpaper_manager->SetUserWallpaperNow(test_account_id2_);
+  wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished();
+  EXPECT_TRUE(wallpaper_manager_test_utils::ImageIsNearColor(
+      controller_->GetWallpaper(),
+      wallpaper_manager_test_utils::kCustomWallpaperColor));
+
+  // Now simulate the lost of |test_account_id1_|'s wallpaper by only updating
+  // its WallpaperInfo but not providing its wallpaper. In this case we just
+  // fallback to the default wallpaper.
+  std::string relative_path =
+      base::FilePath(test_account1_wallpaper_files_id_.id()).Append(id).value();
+  // Saves wallpaper info to local state for user |test_account_id1_|.
+  WallpaperInfo info = {relative_path, WALLPAPER_LAYOUT_CENTER_CROPPED,
+                        wallpaper::CUSTOMIZED,
+                        base::Time::Now().LocalMidnight()};
+  wallpaper_manager->SetUserWallpaperInfo(test_account_id1_, info, true);
+
+  // Now simulate lock/login screen. On lock/login screen all user's wallpapers
+  // will be cached. Test that caching |test_account_id1_| wallpaper won't
+  // change the current wallpaper (|teset_account_id2_|'s wallpaper).
+  CacheUserWallpaper(test_account_id1_);
+  wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished();
+  EXPECT_TRUE(wallpaper_manager_test_utils::ImageIsNearColor(
+      controller_->GetWallpaper(),
+      wallpaper_manager_test_utils::kCustomWallpaperColor));
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc
index ce6f876..3ef7c4b 100644
--- a/chrome/browser/chromeos/login/wizard_controller.cc
+++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -651,6 +651,15 @@
 }
 
 void WizardController::ShowWaitForContainerReadyScreen() {
+  DCHECK(is_in_session_oobe_);
+  // At this point we could make sure the value prop flow has been accepted.
+  // Set the value prop pref as accepted in framework service.
+  auto* service =
+      arc::ArcVoiceInteractionFrameworkService::GetForBrowserContext(
+          ProfileManager::GetActiveUserProfile());
+  if (service)
+    service->SetVoiceInteractionSetupCompleted();
+
   UpdateStatusAreaVisibilityForScreen(
       OobeScreen::SCREEN_WAIT_FOR_CONTAINER_READY);
   SetCurrentScreen(GetScreen(OobeScreen::SCREEN_WAIT_FOR_CONTAINER_READY));
@@ -846,8 +855,6 @@
 
 void WizardController::OnArcTermsOfServiceSkipped() {
   if (is_in_session_oobe_) {
-    PrefService* prefs = ProfileManager::GetActiveUserProfile()->GetPrefs();
-    prefs->SetBoolean(prefs::kArcVoiceInteractionValuePropAccepted, false);
     OnOobeFlowFinished();
     return;
   }
diff --git a/chrome/browser/chromeos/net/network_portal_notification_controller.cc b/chrome/browser/chromeos/net/network_portal_notification_controller.cc
index fcf4817..df09ec3 100644
--- a/chrome/browser/chromeos/net/network_portal_notification_controller.cc
+++ b/chrome/browser/chromeos/net/network_portal_notification_controller.cc
@@ -21,6 +21,7 @@
 #include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/mobile/mobile_activator.h"
@@ -340,16 +341,19 @@
       ash::system_notifier::kNotifierNetworkPortalDetector);
   base::string16 notificationText;
   bool is_wifi = NetworkTypePattern::WiFi().MatchesType(network->type());
-  std::unique_ptr<Notification> notification(new Notification(
-      message_center::NOTIFICATION_TYPE_SIMPLE, kNotificationId,
-      l10n_util::GetStringUTF16(
-          is_wifi ? IDS_PORTAL_DETECTION_NOTIFICATION_TITLE_WIFI
-                  : IDS_PORTAL_DETECTION_NOTIFICATION_TITLE_WIRED),
-      l10n_util::GetStringFUTF16(
-          is_wifi ? IDS_PORTAL_DETECTION_NOTIFICATION_MESSAGE_WIFI
-                  : IDS_PORTAL_DETECTION_NOTIFICATION_MESSAGE_WIRED,
-          base::UTF8ToUTF16(network->name())),
-      icon, base::string16(), GURL(), notifier_id, data, delegate.get()));
+  std::unique_ptr<Notification> notification =
+      ash::system_notifier::CreateSystemNotification(
+          message_center::NOTIFICATION_TYPE_SIMPLE, kNotificationId,
+          l10n_util::GetStringUTF16(
+              is_wifi ? IDS_PORTAL_DETECTION_NOTIFICATION_TITLE_WIFI
+                      : IDS_PORTAL_DETECTION_NOTIFICATION_TITLE_WIRED),
+          l10n_util::GetStringFUTF16(
+              is_wifi ? IDS_PORTAL_DETECTION_NOTIFICATION_MESSAGE_WIFI
+                      : IDS_PORTAL_DETECTION_NOTIFICATION_MESSAGE_WIRED,
+              base::UTF8ToUTF16(network->name())),
+          icon, base::string16(), GURL(), notifier_id, data, delegate.get(),
+          kNotificationCaptivePortalIcon,
+          message_center::SystemNotificationWarningLevel::NORMAL);
   notification->SetSystemPriority();
   return notification;
 }
@@ -396,11 +400,14 @@
     data.buttons.push_back(message_center::ButtonInfo(l10n_util::GetStringUTF16(
         IDS_PORTAL_DETECTION_NOTIFICATION_BUTTON_PORTAL)));
   }
-  std::unique_ptr<Notification> notification(new Notification(
-      message_center::NOTIFICATION_TYPE_SIMPLE, kNotificationId,
-      l10n_util::GetStringUTF16(IDS_PORTAL_DETECTION_NOTIFICATION_TITLE_WIFI),
-      notificationText, icon, base::string16() /* display_source */, GURL(),
-      notifier_id, data, delegate.get()));
+  std::unique_ptr<Notification> notification =
+      ash::system_notifier::CreateSystemNotification(
+          message_center::NOTIFICATION_TYPE_SIMPLE, kNotificationId,
+          l10n_util::GetStringUTF16(
+              IDS_PORTAL_DETECTION_NOTIFICATION_TITLE_WIFI),
+          notificationText, icon, base::string16() /* display_source */, GURL(),
+          notifier_id, data, delegate.get(), kNotificationCaptivePortalIcon,
+          message_center::SystemNotificationWarningLevel::NORMAL);
   notification->SetSystemPriority();
   return notification;
 }
diff --git a/chrome/browser/chromeos/net/tether_notification_presenter.cc b/chrome/browser/chromeos/net/tether_notification_presenter.cc
index 8b879cd..dc16a95 100644
--- a/chrome/browser/chromeos/net/tether_notification_presenter.cc
+++ b/chrome/browser/chromeos/net/tether_notification_presenter.cc
@@ -158,7 +158,8 @@
                << "device with name \"" << remote_device.name << "\". "
                << "Notification ID = " << kPotentialHotspotNotificationId;
 
-  hotspot_nearby_device_ = remote_device;
+  hotspot_nearby_device_id_ =
+      base::MakeUnique<std::string>(remote_device.GetDeviceId());
 
   message_center::RichNotificationData rich_notification_data;
   rich_notification_data.buttons.push_back(
@@ -170,7 +171,7 @@
           IDS_TETHER_NOTIFICATION_WIFI_AVAILABLE_ONE_DEVICE_TITLE),
       l10n_util::GetStringFUTF16(
           IDS_TETHER_NOTIFICATION_WIFI_AVAILABLE_ONE_DEVICE_MESSAGE,
-          base::ASCIIToUTF16(hotspot_nearby_device_.name)),
+          base::ASCIIToUTF16(remote_device.name)),
       rich_notification_data, signal_strength));
 }
 
@@ -179,6 +180,8 @@
                << "multiple devices. Notification ID = "
                << kPotentialHotspotNotificationId;
 
+  hotspot_nearby_device_id_.reset();
+
   ShowNotification(CreateNotificationWithMediumSignalStrengthIcon(
       kPotentialHotspotNotificationId,
       l10n_util::GetStringUTF16(
@@ -187,6 +190,21 @@
           IDS_TETHER_NOTIFICATION_WIFI_AVAILABLE_MULTIPLE_DEVICES_MESSAGE)));
 }
 
+NotificationPresenter::PotentialHotspotNotificationState
+TetherNotificationPresenter::GetPotentialHotspotNotificationState() {
+  if (!message_center_->FindVisibleNotificationById(
+          kPotentialHotspotNotificationId)) {
+    return NotificationPresenter::PotentialHotspotNotificationState::
+        NO_HOTSPOT_NOTIFICATION_SHOWN;
+  }
+
+  return hotspot_nearby_device_id_
+             ? NotificationPresenter::PotentialHotspotNotificationState::
+                   SINGLE_HOTSPOT_NEARBY_SHOWN
+             : NotificationPresenter::PotentialHotspotNotificationState::
+                   MULTIPLE_HOTSPOTS_NEARBY_SHOWN;
+}
+
 void TetherNotificationPresenter::RemovePotentialHotspotNotification() {
   RemoveNotificationIfVisible(kPotentialHotspotNotificationId);
 }
@@ -267,14 +285,15 @@
 void TetherNotificationPresenter::OnNotificationButtonClicked(
     const std::string& notification_id,
     int button_index) {
-  PA_LOG(INFO) << "Button at index " << button_index
-               << " of notification with ID " << notification_id
-               << " was clicked.";
+  if (notification_id != kPotentialHotspotNotificationId)
+    return;
 
-  if (notification_id == kPotentialHotspotNotificationId && button_index == 0) {
-    network_connect_->ConnectToNetworkId(hotspot_nearby_device_.GetDeviceId());
-  }
-  message_center_->RemoveNotification(notification_id, true /* by_user */);
+  DCHECK(button_index == 0);
+  DCHECK(hotspot_nearby_device_id_);
+  PA_LOG(INFO) << "\"Potential hotspot nearby\" notification button was "
+               << "clicked.";
+  network_connect_->ConnectToNetworkId(*hotspot_nearby_device_id_);
+  RemoveNotificationIfVisible(kPotentialHotspotNotificationId);
 }
 
 void TetherNotificationPresenter::SetSettingsUiDelegateForTesting(
@@ -301,11 +320,14 @@
 
   settings_ui_delegate_->ShowSettingsSubPageForProfile(profile_,
                                                        settings_subpage);
-  message_center_->RemoveNotification(notification_id, true /* by_user */);
+  RemoveNotificationIfVisible(notification_id);
 }
 
 void TetherNotificationPresenter::RemoveNotificationIfVisible(
     const std::string& notification_id) {
+  if (notification_id == kPotentialHotspotNotificationId)
+    hotspot_nearby_device_id_.reset();
+
   if (!message_center_->FindVisibleNotificationById(notification_id))
     return;
 
diff --git a/chrome/browser/chromeos/net/tether_notification_presenter.h b/chrome/browser/chromeos/net/tether_notification_presenter.h
index 67d297c..cd68c1f6 100644
--- a/chrome/browser/chromeos/net/tether_notification_presenter.h
+++ b/chrome/browser/chromeos/net/tether_notification_presenter.h
@@ -49,6 +49,8 @@
       const cryptauth::RemoteDevice& remote_device,
       int signal_strength) override;
   void NotifyMultiplePotentialHotspotsNearby() override;
+  NotificationPresenter::PotentialHotspotNotificationState
+  GetPotentialHotspotNotificationState() override;
   void RemovePotentialHotspotNotification() override;
   void NotifySetupRequired(const std::string& device_name) override;
   void RemoveSetupRequiredNotification() override;
@@ -98,7 +100,10 @@
 
   std::unique_ptr<SettingsUiDelegate> settings_ui_delegate_;
 
-  cryptauth::RemoteDevice hotspot_nearby_device_;
+  // The device ID of the device whose metadata is displayed in the "potential
+  // hotspot nearby" notification. If the notification is not visible or it is
+  // in the "multiple hotspots available" mode, this pointer is null.
+  std::unique_ptr<std::string> hotspot_nearby_device_id_;
   base::WeakPtrFactory<TetherNotificationPresenter> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(TetherNotificationPresenter);
diff --git a/chrome/browser/chromeos/net/tether_notification_presenter_unittest.cc b/chrome/browser/chromeos/net/tether_notification_presenter_unittest.cc
index 9e0fe332..2672524 100644
--- a/chrome/browser/chromeos/net/tether_notification_presenter_unittest.cc
+++ b/chrome/browser/chromeos/net/tether_notification_presenter_unittest.cc
@@ -486,6 +486,80 @@
   VerifySettingsNotOpened();
 }
 
+TEST_F(TetherNotificationPresenterTest,
+       TestGetPotentialHotspotNotificationState) {
+  EXPECT_EQ(notification_presenter_->GetPotentialHotspotNotificationState(),
+            NotificationPresenter::PotentialHotspotNotificationState::
+                NO_HOTSPOT_NOTIFICATION_SHOWN);
+
+  // Notify single host available and remove.
+  notification_presenter_->NotifyPotentialHotspotNearby(
+      test_device_, kTestNetworkSignalStrength);
+  EXPECT_EQ(notification_presenter_->GetPotentialHotspotNotificationState(),
+            NotificationPresenter::PotentialHotspotNotificationState::
+                SINGLE_HOTSPOT_NEARBY_SHOWN);
+  notification_presenter_->RemovePotentialHotspotNotification();
+  EXPECT_EQ(notification_presenter_->GetPotentialHotspotNotificationState(),
+            NotificationPresenter::PotentialHotspotNotificationState::
+                NO_HOTSPOT_NOTIFICATION_SHOWN);
+
+  // Notify single host available and remove by tapping notification.
+  notification_presenter_->NotifyPotentialHotspotNearby(
+      test_device_, kTestNetworkSignalStrength);
+  EXPECT_EQ(notification_presenter_->GetPotentialHotspotNotificationState(),
+            NotificationPresenter::PotentialHotspotNotificationState::
+                SINGLE_HOTSPOT_NEARBY_SHOWN);
+  test_message_center_->NotifyNotificationTapped(
+      GetPotentialHotspotNotificationId());
+  EXPECT_EQ(notification_presenter_->GetPotentialHotspotNotificationState(),
+            NotificationPresenter::PotentialHotspotNotificationState::
+                NO_HOTSPOT_NOTIFICATION_SHOWN);
+
+  // Notify single host available and remove by tapping notification button.
+  notification_presenter_->NotifyPotentialHotspotNearby(
+      test_device_, kTestNetworkSignalStrength);
+  EXPECT_EQ(notification_presenter_->GetPotentialHotspotNotificationState(),
+            NotificationPresenter::PotentialHotspotNotificationState::
+                SINGLE_HOTSPOT_NEARBY_SHOWN);
+  test_message_center_->NotifyNotificationButtonTapped(
+      GetPotentialHotspotNotificationId(), 0 /* button_index */);
+  EXPECT_EQ(notification_presenter_->GetPotentialHotspotNotificationState(),
+            NotificationPresenter::PotentialHotspotNotificationState::
+                NO_HOTSPOT_NOTIFICATION_SHOWN);
+
+  // Notify single, then multiple hosts available and remove.
+  notification_presenter_->NotifyPotentialHotspotNearby(
+      test_device_, kTestNetworkSignalStrength);
+  EXPECT_EQ(notification_presenter_->GetPotentialHotspotNotificationState(),
+            NotificationPresenter::PotentialHotspotNotificationState::
+                SINGLE_HOTSPOT_NEARBY_SHOWN);
+  notification_presenter_->NotifyMultiplePotentialHotspotsNearby();
+  EXPECT_EQ(notification_presenter_->GetPotentialHotspotNotificationState(),
+            NotificationPresenter::PotentialHotspotNotificationState::
+                MULTIPLE_HOTSPOTS_NEARBY_SHOWN);
+  notification_presenter_->RemovePotentialHotspotNotification();
+  EXPECT_EQ(notification_presenter_->GetPotentialHotspotNotificationState(),
+            NotificationPresenter::PotentialHotspotNotificationState::
+                NO_HOTSPOT_NOTIFICATION_SHOWN);
+
+  // Notify single, then multiple hosts available and remove by tapping
+  // notification.
+  notification_presenter_->NotifyPotentialHotspotNearby(
+      test_device_, kTestNetworkSignalStrength);
+  EXPECT_EQ(notification_presenter_->GetPotentialHotspotNotificationState(),
+            NotificationPresenter::PotentialHotspotNotificationState::
+                SINGLE_HOTSPOT_NEARBY_SHOWN);
+  notification_presenter_->NotifyMultiplePotentialHotspotsNearby();
+  EXPECT_EQ(notification_presenter_->GetPotentialHotspotNotificationState(),
+            NotificationPresenter::PotentialHotspotNotificationState::
+                MULTIPLE_HOTSPOTS_NEARBY_SHOWN);
+  test_message_center_->NotifyNotificationTapped(
+      GetPotentialHotspotNotificationId());
+  EXPECT_EQ(notification_presenter_->GetPotentialHotspotNotificationState(),
+            NotificationPresenter::PotentialHotspotNotificationState::
+                NO_HOTSPOT_NOTIFICATION_SHOWN);
+}
+
 }  // namespace tether
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/preferences.cc b/chrome/browser/chromeos/preferences.cc
index c309776..6c77943e 100644
--- a/chrome/browser/chromeos/preferences.cc
+++ b/chrome/browser/chromeos/preferences.cc
@@ -131,9 +131,8 @@
 
   registry->RegisterStringPref(prefs::kCastReceiverName, "");
 
-  // Register ash prefs.
-  if (!ash_util::IsRunningInMash())
-    ash::Shell::RegisterLocalStatePrefs(registry);
+  registry->RegisterDictionaryPref(ash::prefs::kWallpaperColors,
+                                   PrefRegistry::PUBLIC);
 }
 
 // static
diff --git a/chrome/browser/content_settings/host_content_settings_map_unittest.cc b/chrome/browser/content_settings/host_content_settings_map_unittest.cc
index 92ddec81..db250d994 100644
--- a/chrome/browser/content_settings/host_content_settings_map_unittest.cc
+++ b/chrome/browser/content_settings/host_content_settings_map_unittest.cc
@@ -286,6 +286,85 @@
   EXPECT_EQ(1U, host_settings.size());
 }
 
+TEST_F(HostContentSettingsMapTest, GetWebsiteSettingsForOneType) {
+  TestingProfile profile;
+  GURL hosts[] = {GURL("https://example1.com/"), GURL("https://example2.com/")};
+  ContentSettingsForOneType client_hints_settings;
+  HostContentSettingsMap* host_content_settings_map =
+      HostContentSettingsMapFactory::GetForProfile(&profile);
+
+  host_content_settings_map->GetSettingsForOneType(
+      CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
+      &client_hints_settings);
+  EXPECT_EQ(0U, client_hints_settings.size());
+
+  // Add setting for hosts[0].
+  const double expiration_time =
+      (base::Time::Now() + base::TimeDelta::FromDays(1)).ToDoubleT();
+  std::unique_ptr<base::ListValue> expiration_times_list =
+      base::MakeUnique<base::ListValue>();
+  expiration_times_list->AppendInteger(42 /* client hint  value */);
+  auto expiration_times_dictionary = std::make_unique<base::DictionaryValue>();
+  expiration_times_dictionary->SetList("client_hints",
+                                       std::move(expiration_times_list));
+  expiration_times_dictionary->SetDouble("expiration_time", expiration_time);
+  host_content_settings_map->SetWebsiteSettingDefaultScope(
+      hosts[0], GURL(), CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
+      base::MakeUnique<base::Value>(expiration_times_dictionary->Clone()));
+
+  // Reading the settings should now return one setting.
+  host_content_settings_map->GetSettingsForOneType(
+      CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
+      &client_hints_settings);
+  EXPECT_EQ(1U, client_hints_settings.size());
+  for (size_t i = 0; i < client_hints_settings.size(); ++i) {
+    EXPECT_EQ(ContentSettingsPattern::FromURLNoWildcard(hosts[i]),
+              client_hints_settings.at(i).primary_pattern);
+    EXPECT_EQ(ContentSettingsPattern::Wildcard(),
+              client_hints_settings.at(i).secondary_pattern);
+    EXPECT_EQ(*expiration_times_dictionary,
+              *client_hints_settings.at(i).setting_value);
+  }
+
+  // Add setting for hosts[1].
+  host_content_settings_map->SetWebsiteSettingDefaultScope(
+      hosts[1], GURL(), CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
+      base::MakeUnique<base::Value>(expiration_times_dictionary->Clone()));
+
+  // Reading the settings should now return two settings.
+  host_content_settings_map->GetSettingsForOneType(
+      CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
+      &client_hints_settings);
+  EXPECT_EQ(2U, client_hints_settings.size());
+  for (size_t i = 0; i < client_hints_settings.size(); ++i) {
+    EXPECT_EQ(ContentSettingsPattern::FromURLNoWildcard(hosts[i]),
+              client_hints_settings.at(i).primary_pattern);
+    EXPECT_EQ(ContentSettingsPattern::Wildcard(),
+              client_hints_settings.at(i).secondary_pattern);
+    EXPECT_EQ(*expiration_times_dictionary,
+              *client_hints_settings.at(i).setting_value);
+  }
+
+  // Add settings again for hosts[0].
+  host_content_settings_map->SetWebsiteSettingDefaultScope(
+      hosts[0], GURL(), CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
+      base::MakeUnique<base::Value>(expiration_times_dictionary->Clone()));
+
+  // Reading the settings should still return two settings.
+  host_content_settings_map->GetSettingsForOneType(
+      CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
+      &client_hints_settings);
+  EXPECT_EQ(2U, client_hints_settings.size());
+  for (size_t i = 0; i < client_hints_settings.size(); ++i) {
+    EXPECT_EQ(ContentSettingsPattern::FromURLNoWildcard(hosts[i]),
+              client_hints_settings.at(i).primary_pattern);
+    EXPECT_EQ(ContentSettingsPattern::Wildcard(),
+              client_hints_settings.at(i).secondary_pattern);
+    EXPECT_EQ(*expiration_times_dictionary,
+              *client_hints_settings.at(i).setting_value);
+  }
+}
+
 TEST_F(HostContentSettingsMapTest, Clear) {
   TestingProfile profile;
   HostContentSettingsMap* host_content_settings_map =
diff --git a/chrome/browser/data_usage/tab_id_annotator.cc b/chrome/browser/data_usage/tab_id_annotator.cc
index 2f33cca..64168b8 100644
--- a/chrome/browser/data_usage/tab_id_annotator.cc
+++ b/chrome/browser/data_usage/tab_id_annotator.cc
@@ -32,18 +32,15 @@
 // Attempts to get the associated tab info for render frame identified by
 // |render_process_id| and |render_frame_id|. |global_request_id| is also
 // populated in the tab info.
-TabIdProvider::URLRequestTabInfo GetTabInfoForRequest(
-    int render_process_id,
-    int render_frame_id,
-    content::GlobalRequestID global_request_id) {
+int32_t GetTabInfoForRequest(int render_process_id,
+                             int render_frame_id,
+                             content::GlobalRequestID global_request_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   // TODO(sclittle): For prerendering tabs, investigate if it's possible to find
   // the original tab that initiated the prerender.
-  return TabIdProvider::URLRequestTabInfo(
-      SessionTabHelper::IdForTab(content::WebContents::FromRenderFrameHost(
-          content::RenderFrameHost::FromID(render_process_id,
-                                           render_frame_id))),
-      global_request_id);
+
+  return SessionTabHelper::IdForTab(content::WebContents::FromRenderFrameHost(
+      content::RenderFrameHost::FromID(render_process_id, render_frame_id)));
 }
 
 // Annotates |data_use| with the given |tab_id|, then passes it to |callback|.
@@ -54,13 +51,11 @@
 void AnnotateDataUse(
     std::unique_ptr<DataUse> data_use,
     const data_usage::DataUseAnnotator::DataUseConsumerCallback& callback,
-    TabIdProvider::URLRequestTabInfo tab_info) {
+    int32_t tab_info) {
   DCHECK(data_use);
-  data_use->tab_id = tab_info.tab_id;
-  data_use->main_frame_global_request_id.first =
-      tab_info.main_frame_global_request_id.child_id;
-  data_use->main_frame_global_request_id.second =
-      tab_info.main_frame_global_request_id.request_id;
+  data_use->tab_id = tab_info;
+  data_use->main_frame_global_request_id =
+      data_usage::DataUse::kInvalidMainFrameGlobalRequestID;
   callback.Run(std::move(data_use));
 }
 
@@ -90,9 +85,7 @@
           request, &render_process_id, &render_frame_id)) {
     // Run the callback immediately with a tab ID of -1 if the request has no
     // render frame.
-    AnnotateDataUse(std::move(data_use), callback,
-                    TabIdProvider::URLRequestTabInfo(
-                        -1 /* tab_id */, content::GlobalRequestID()));
+    AnnotateDataUse(std::move(data_use), callback, -1 /* tab_id */);
     return;
   }
 
diff --git a/chrome/browser/data_usage/tab_id_annotator_unittest.cc b/chrome/browser/data_usage/tab_id_annotator_unittest.cc
index 698e43a..1cebdce 100644
--- a/chrome/browser/data_usage/tab_id_annotator_unittest.cc
+++ b/chrome/browser/data_usage/tab_id_annotator_unittest.cc
@@ -58,9 +58,6 @@
   auto data_use = std::unique_ptr<DataUse>(new DataUse(
       GURL("http://foo.com"), base::TimeTicks(), GURL(), tab_id,
       net::NetworkChangeNotifier::CONNECTION_UNKNOWN, std::string(), 100, 100));
-  if (render_process_id != -1)
-    data_use->main_frame_global_request_id =
-        std::make_pair(render_process_id, 0);
   return data_use;
 }
 
diff --git a/chrome/browser/data_usage/tab_id_provider.cc b/chrome/browser/data_usage/tab_id_provider.cc
index c576fa1..52debf16 100644
--- a/chrome/browser/data_usage/tab_id_provider.cc
+++ b/chrome/browser/data_usage/tab_id_provider.cc
@@ -21,8 +21,8 @@
 namespace {
 
 // Convenience typedefs for clarity.
-typedef base::Callback<TabIdProvider::URLRequestTabInfo(void)> TabIdGetter;
-typedef base::Callback<void(TabIdProvider::URLRequestTabInfo)> TabIdCallback;
+typedef base::Callback<int32_t(void)> TabIdGetter;
+typedef base::Callback<void(int32_t)> TabIdCallback;
 
 }  // namespace
 
@@ -36,7 +36,7 @@
   ~CallbackRunner() {
     // Ensure that no callbacks are abandoned without being run.
     if (!is_done_)
-      RunAll(URLRequestTabInfo(-1, content::GlobalRequestID()));
+      RunAll(-1);
   }
 
   // Adds a new callback to be run later. New callbacks must not be added after
@@ -49,7 +49,7 @@
 
   // Runs all the callbacks in the order that they were added. This method must
   // not be called more than once.
-  void RunAll(TabIdProvider::URLRequestTabInfo tab_info) {
+  void RunAll(int32_t tab_info) {
     DCHECK(thread_checker_.CalledOnValidThread());
     DCHECK(!is_done_);
     is_done_ = true;
@@ -78,9 +78,7 @@
 TabIdProvider::TabIdProvider(base::TaskRunner* task_runner,
                              const tracked_objects::Location& from_here,
                              const TabIdGetter& tab_id_getter)
-    : is_tab_info_ready_(false),
-      tab_info_(-1, content::GlobalRequestID()),
-      weak_ptr_factory_(this) {
+    : is_tab_info_ready_(false), tab_info_(-1), weak_ptr_factory_(this) {
   std::unique_ptr<CallbackRunner> callback_runner(new CallbackRunner());
   weak_callback_runner_ = callback_runner->GetWeakPtr();
   callback_runner->AddCallback(
@@ -111,7 +109,7 @@
   // If no cached tab ID is available and |weak_callback_runner_| has been
   // destroyed, pass a tab ID of -1 to the callback indicating that no tab was
   // found.
-  callback.Run(URLRequestTabInfo(-1, content::GlobalRequestID()));
+  callback.Run(-1);
 }
 
 base::WeakPtr<TabIdProvider> TabIdProvider::GetWeakPtr() {
@@ -123,7 +121,7 @@
 const void* const TabIdProvider::kTabIdProviderUserDataKey =
     "TabIdProviderUserDataKey";
 
-void TabIdProvider::OnTabIdReady(URLRequestTabInfo tab_info) {
+void TabIdProvider::OnTabIdReady(int32_t tab_info) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!is_tab_info_ready_);
   tab_info_ = tab_info;
diff --git a/chrome/browser/data_usage/tab_id_provider.h b/chrome/browser/data_usage/tab_id_provider.h
index f7da97f..ab02de9b 100644
--- a/chrome/browser/data_usage/tab_id_provider.h
+++ b/chrome/browser/data_usage/tab_id_provider.h
@@ -54,13 +54,13 @@
   // |task_runner|.
   TabIdProvider(base::TaskRunner* task_runner,
                 const tracked_objects::Location& from_here,
-                const base::Callback<URLRequestTabInfo(void)>& tab_id_getter);
+                const base::Callback<int32_t(void)>& tab_id_getter);
 
   ~TabIdProvider() override;
 
   // Calls |callback| with the tab ID, either immediately if it's already
   // available, or later once it becomes available.
-  void ProvideTabId(const base::Callback<void(URLRequestTabInfo)>& callback);
+  void ProvideTabId(const base::Callback<void(int32_t)>& callback);
 
   base::WeakPtr<TabIdProvider> GetWeakPtr();
 
@@ -70,11 +70,11 @@
   class CallbackRunner;
 
   // Called when the |tab_info| is ready.
-  void OnTabIdReady(URLRequestTabInfo tab_info);
+  void OnTabIdReady(int32_t tab_info);
 
   base::ThreadChecker thread_checker_;
   bool is_tab_info_ready_;
-  URLRequestTabInfo tab_info_;
+  int32_t tab_info_;
   base::WeakPtr<CallbackRunner> weak_callback_runner_;
   base::WeakPtrFactory<TabIdProvider> weak_ptr_factory_;
 
diff --git a/chrome/browser/data_usage/tab_id_provider_unittest.cc b/chrome/browser/data_usage/tab_id_provider_unittest.cc
index 36093e4..c00fff83 100644
--- a/chrome/browser/data_usage/tab_id_provider_unittest.cc
+++ b/chrome/browser/data_usage/tab_id_provider_unittest.cc
@@ -34,7 +34,7 @@
 
   ~TabIdProviderTest() override {}
 
-  base::Callback<TabIdProvider::URLRequestTabInfo(void)> TabIdGetterCallback() {
+  base::Callback<int32_t(void)> TabIdGetterCallback() {
     return base::Bind(&TabIdProviderTest::GetTabInfo, base::Unretained(this));
   }
 
@@ -43,9 +43,9 @@
   int tab_id_getter_call_count() const { return tab_id_getter_call_count_; }
 
  private:
-  TabIdProvider::URLRequestTabInfo GetTabInfo() {
+  int32_t GetTabInfo() {
     ++tab_id_getter_call_count_;
-    return TabIdProvider::URLRequestTabInfo(kTabId, content::GlobalRequestID());
+    return kTabId;
   }
 
   base::MessageLoop message_loop_;
@@ -57,8 +57,8 @@
 };
 
 // Copies |tab_id| into |capture|.
-void CaptureTabId(int32_t* capture, TabIdProvider::URLRequestTabInfo tab_info) {
-  *capture = tab_info.tab_id;
+void CaptureTabId(int32_t* capture, int32_t tab_info) {
+  *capture = tab_info;
 }
 
 TEST_F(TabIdProviderTest, ProvideTabId) {
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn
index a5e99251..975a2f1 100644
--- a/chrome/browser/extensions/BUILD.gn
+++ b/chrome/browser/extensions/BUILD.gn
@@ -322,10 +322,6 @@
     "api/permissions/permissions_api.h",
     "api/permissions/permissions_api_helpers.cc",
     "api/permissions/permissions_api_helpers.h",
-    "api/preference/chrome_direct_setting.cc",
-    "api/preference/chrome_direct_setting.h",
-    "api/preference/chrome_direct_setting_api.cc",
-    "api/preference/chrome_direct_setting_api.h",
     "api/preference/preference_api.cc",
     "api/preference/preference_api.h",
     "api/preference/preference_api_constants.cc",
diff --git a/chrome/browser/extensions/api/omnibox/omnibox_api.cc b/chrome/browser/extensions/api/omnibox/omnibox_api.cc
index 2d9854e..6fcfcfd 100644
--- a/chrome/browser/extensions/api/omnibox/omnibox_api.cc
+++ b/chrome/browser/extensions/api/omnibox/omnibox_api.cc
@@ -212,12 +212,11 @@
   if (!keyword.empty()) {
     // Load the omnibox icon so it will be ready to display in the URL bar.
     omnibox_icon_manager_.LoadIcon(profile_, extension);
-
     if (url_service_) {
       url_service_->Load();
       if (url_service_->loaded()) {
         url_service_->RegisterOmniboxKeyword(
-            extension->id(), extension->name(), keyword,
+            extension->id(), extension->short_name(), keyword,
             GetTemplateURLStringForExtension(extension->id()),
             ExtensionPrefs::Get(profile_)->GetInstallTime(extension->id()));
       } else {
@@ -249,7 +248,7 @@
   template_url_sub_.reset();
   for (const auto* i : pending_extensions_) {
     url_service_->RegisterOmniboxKeyword(
-        i->id(), i->name(), OmniboxInfo::GetKeyword(i),
+        i->id(), i->short_name(), OmniboxInfo::GetKeyword(i),
         GetTemplateURLStringForExtension(i->id()),
         ExtensionPrefs::Get(profile_)->GetInstallTime(i->id()));
   }
diff --git a/chrome/browser/extensions/api/preference/chrome_direct_setting.cc b/chrome/browser/extensions/api/preference/chrome_direct_setting.cc
deleted file mode 100644
index db511d0..0000000
--- a/chrome/browser/extensions/api/preference/chrome_direct_setting.cc
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/extensions/api/preference/chrome_direct_setting.h"
-
-#include <utility>
-
-#include "base/containers/hash_tables.h"
-#include "base/lazy_instance.h"
-#include "base/values.h"
-#include "chrome/browser/extensions/api/preference/chrome_direct_setting_api.h"
-#include "chrome/browser/extensions/api/preference/preference_api_constants.h"
-#include "chrome/browser/profiles/profile.h"
-#include "components/prefs/pref_service.h"
-
-namespace extensions {
-namespace chromedirectsetting {
-
-DirectSettingFunctionBase::DirectSettingFunctionBase() {}
-
-DirectSettingFunctionBase::~DirectSettingFunctionBase() {}
-
-PrefService* DirectSettingFunctionBase::GetPrefService() {
-  return Profile::FromBrowserContext(browser_context())->GetPrefs();
-}
-
-GetDirectSettingFunction::GetDirectSettingFunction() {}
-
-ExtensionFunction::ResponseAction GetDirectSettingFunction::Run() {
-  std::string pref_key;
-  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &pref_key));
-  EXTENSION_FUNCTION_VALIDATE(ChromeDirectSettingAPI::Get(browser_context())
-                                  ->IsPreferenceOnWhitelist(pref_key));
-
-  const PrefService::Preference* preference =
-      GetPrefService()->FindPreference(pref_key.c_str());
-  EXTENSION_FUNCTION_VALIDATE(preference);
-  const base::Value* value = preference->GetValue();
-
-  std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue);
-  result->Set(preference_api_constants::kValue, value->CreateDeepCopy());
-  return RespondNow(OneArgument(std::move(result)));
-}
-
-GetDirectSettingFunction::~GetDirectSettingFunction() {}
-
-SetDirectSettingFunction::SetDirectSettingFunction() {}
-
-ExtensionFunction::ResponseAction SetDirectSettingFunction::Run() {
-  std::string pref_key;
-  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &pref_key));
-  EXTENSION_FUNCTION_VALIDATE(ChromeDirectSettingAPI::Get(browser_context())
-                                  ->IsPreferenceOnWhitelist(pref_key));
-
-  base::DictionaryValue* details = NULL;
-  EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &details));
-
-  base::Value* value = NULL;
-  EXTENSION_FUNCTION_VALIDATE(
-      details->Get(preference_api_constants::kValue, &value));
-
-  PrefService* pref_service = GetPrefService();
-  const PrefService::Preference* preference =
-      pref_service->FindPreference(pref_key.c_str());
-  EXTENSION_FUNCTION_VALIDATE(preference);
-
-  EXTENSION_FUNCTION_VALIDATE(value->GetType() == preference->GetType());
-
-  pref_service->Set(pref_key.c_str(), *value);
-
-  return RespondNow(NoArguments());
-}
-
-SetDirectSettingFunction::~SetDirectSettingFunction() {}
-
-ClearDirectSettingFunction::ClearDirectSettingFunction() {}
-
-ExtensionFunction::ResponseAction ClearDirectSettingFunction::Run() {
-  std::string pref_key;
-  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &pref_key));
-  EXTENSION_FUNCTION_VALIDATE(ChromeDirectSettingAPI::Get(browser_context())
-                                  ->IsPreferenceOnWhitelist(pref_key));
-  GetPrefService()->ClearPref(pref_key.c_str());
-
-  return RespondNow(NoArguments());
-}
-
-ClearDirectSettingFunction::~ClearDirectSettingFunction() {}
-
-}  // namespace chromedirectsetting
-}  // namespace extensions
-
diff --git a/chrome/browser/extensions/api/preference/chrome_direct_setting.h b/chrome/browser/extensions/api/preference/chrome_direct_setting.h
deleted file mode 100644
index c58cab2..0000000
--- a/chrome/browser/extensions/api/preference/chrome_direct_setting.h
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_EXTENSIONS_API_PREFERENCE_CHROME_DIRECT_SETTING_H__
-#define CHROME_BROWSER_EXTENSIONS_API_PREFERENCE_CHROME_DIRECT_SETTING_H__
-
-#include "base/lazy_instance.h"
-#include "base/macros.h"
-#include "extensions/browser/extension_function.h"
-
-class PrefService;
-
-namespace extensions {
-namespace chromedirectsetting {
-
-// Base class to host instance method helpers.
-class DirectSettingFunctionBase : public UIThreadExtensionFunction {
- protected:
-  DirectSettingFunctionBase();
-  ~DirectSettingFunctionBase() override;
-
-  // Returns the user pref service.
-  PrefService* GetPrefService();
-
-  // Returns true if the caller is a component extension.
-  bool IsCalledFromComponentExtension();
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(DirectSettingFunctionBase);
-};
-
-class GetDirectSettingFunction : public DirectSettingFunctionBase {
- public:
-  DECLARE_EXTENSION_FUNCTION("types.private.ChromeDirectSetting.get",
-                             TYPES_PRIVATE_CHROMEDIRECTSETTING_GET)
-
-  GetDirectSettingFunction();
-
- protected:
-  // ExtensionFunction:
-  ResponseAction Run() override;
-
- private:
-  ~GetDirectSettingFunction() override;
-  DISALLOW_COPY_AND_ASSIGN(GetDirectSettingFunction);
-};
-
-class SetDirectSettingFunction : public DirectSettingFunctionBase {
- public:
-  DECLARE_EXTENSION_FUNCTION("types.private.ChromeDirectSetting.set",
-                             TYPES_PRIVATE_CHROMEDIRECTSETTING_SET)
-
-  SetDirectSettingFunction();
-
- protected:
-  // ExtensionFunction:
-  ResponseAction Run() override;
-
- private:
-  ~SetDirectSettingFunction() override;
-  DISALLOW_COPY_AND_ASSIGN(SetDirectSettingFunction);
-};
-
-class ClearDirectSettingFunction : public DirectSettingFunctionBase {
- public:
-  DECLARE_EXTENSION_FUNCTION("types.private.ChromeDirectSetting.clear",
-                             TYPES_PRIVATE_CHROMEDIRECTSETTING_CLEAR)
-
-  ClearDirectSettingFunction();
-
- protected:
-  // ExtensionFunction:
-  ResponseAction Run() override;
-
- private:
-  ~ClearDirectSettingFunction() override;
-  DISALLOW_COPY_AND_ASSIGN(ClearDirectSettingFunction);
-};
-
-}  // namespace chromedirectsetting
-}  // namespace extensions
-
-#endif  // CHROME_BROWSER_EXTENSIONS_API_PREFERENCE_CHROME_DIRECT_SETTING_H__
-
diff --git a/chrome/browser/extensions/api/preference/chrome_direct_setting_api.cc b/chrome/browser/extensions/api/preference/chrome_direct_setting_api.cc
deleted file mode 100644
index 5bf1d8f..0000000
--- a/chrome/browser/extensions/api/preference/chrome_direct_setting_api.cc
+++ /dev/null
@@ -1,169 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/extensions/api/preference/chrome_direct_setting_api.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/containers/hash_tables.h"
-#include "base/lazy_instance.h"
-#include "base/macros.h"
-#include "base/strings/stringprintf.h"
-#include "chrome/browser/extensions/api/preference/preference_api_constants.h"
-#include "chrome/browser/profiles/profile.h"
-#include "components/prefs/pref_change_registrar.h"
-#include "components/prefs/pref_service.h"
-#include "extensions/browser/extension_registry.h"
-
-namespace extensions {
-namespace chromedirectsetting {
-
-const char kOnPrefChangeFormat[] =
-    "types.private.ChromeDirectSetting.%s.onChange";
-
-class PreferenceWhitelist {
- public:
-  PreferenceWhitelist() {
-    // Note: DO NOT add any setting here that does not have a UI element in
-    // chrome://settings unless you write a component extension that is always
-    // installed. Otherwise, users may install your extension, the extension may
-    // toggle settings, and after the extension has been disabled/uninstalled
-    // the toggled setting remains in place. See http://crbug.com/164227#c157 .
-    // The following settings need to be checked and probably removed. See
-    // http://crbug.com/164227#c157 .
-    whitelist_.insert("easy_unlock.proximity_required");
-  }
-
-  ~PreferenceWhitelist() {}
-
-  bool IsPreferenceOnWhitelist(const std::string& pref_key){
-    return whitelist_.find(pref_key) != whitelist_.end();
-  }
-
-  void RegisterEventListeners(
-      Profile* profile,
-      EventRouter::Observer* observer) {
-    for (base::hash_set<std::string>::iterator iter = whitelist_.begin();
-         iter != whitelist_.end();
-         iter++) {
-      std::string event_name = base::StringPrintf(
-          kOnPrefChangeFormat,
-          (*iter).c_str());
-      EventRouter::Get(profile)->RegisterObserver(observer, event_name);
-    }
-  }
-
-  void RegisterPropertyListeners(
-      Profile* profile,
-      PrefChangeRegistrar* registrar,
-      const base::Callback<void(const std::string&)>& callback) {
-    for (base::hash_set<std::string>::iterator iter = whitelist_.begin();
-         iter != whitelist_.end();
-         iter++) {
-      const char* pref_key = (*iter).c_str();
-      std::string event_name = base::StringPrintf(
-          kOnPrefChangeFormat,
-          pref_key);
-      registrar->Add(pref_key, callback);
-    }
-  }
-
- private:
-  base::hash_set<std::string> whitelist_;
-
-  DISALLOW_COPY_AND_ASSIGN(PreferenceWhitelist);
-};
-
-base::LazyInstance<PreferenceWhitelist>::DestructorAtExit preference_whitelist =
-    LAZY_INSTANCE_INITIALIZER;
-
-static base::LazyInstance<
-    BrowserContextKeyedAPIFactory<ChromeDirectSettingAPI>>::DestructorAtExit
-    g_factory = LAZY_INSTANCE_INITIALIZER;
-
-ChromeDirectSettingAPI::ChromeDirectSettingAPI(content::BrowserContext* context)
-    : profile_(Profile::FromBrowserContext(context)) {
-  preference_whitelist.Get().RegisterEventListeners(profile_, this);
-}
-
-ChromeDirectSettingAPI::~ChromeDirectSettingAPI() {}
-
-// KeyedService implementation.
-void ChromeDirectSettingAPI::Shutdown() {}
-
-// BrowserContextKeyedAPI implementation.
-BrowserContextKeyedAPIFactory<ChromeDirectSettingAPI>*
-ChromeDirectSettingAPI::GetFactoryInstance() {
-  return g_factory.Pointer();
-}
-
-// EventRouter::Observer implementation.
-void ChromeDirectSettingAPI::OnListenerAdded(const EventListenerInfo& details) {
-  EventRouter::Get(profile_)->UnregisterObserver(this);
-  registrar_.Init(profile_->GetPrefs());
-  preference_whitelist.Get().RegisterPropertyListeners(
-      profile_,
-      &registrar_,
-      base::Bind(&ChromeDirectSettingAPI::OnPrefChanged,
-                 base::Unretained(this),
-                 registrar_.prefs()));
-}
-
-bool ChromeDirectSettingAPI::IsPreferenceOnWhitelist(
-    const std::string& pref_key) {
-  return preference_whitelist.Get().IsPreferenceOnWhitelist(pref_key);
-}
-
-ChromeDirectSettingAPI* ChromeDirectSettingAPI::Get(
-    content::BrowserContext* context) {
-  return BrowserContextKeyedAPIFactory<ChromeDirectSettingAPI>::Get(context);
-}
-
-// BrowserContextKeyedAPI implementation.
-const char* ChromeDirectSettingAPI::service_name() {
-  return "ChromeDirectSettingAPI";
-}
-
-void ChromeDirectSettingAPI::OnPrefChanged(
-    PrefService* pref_service, const std::string& pref_key) {
-  std::string event_name = base::StringPrintf(kOnPrefChangeFormat,
-                                              pref_key.c_str());
-  EventRouter* router = EventRouter::Get(profile_);
-  if (router && router->HasEventListener(event_name)) {
-    const PrefService::Preference* preference =
-        profile_->GetPrefs()->FindPreference(pref_key.c_str());
-    const base::Value* value = preference->GetValue();
-
-    std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue);
-    result->Set(preference_api_constants::kValue, value->CreateDeepCopy());
-    base::ListValue args;
-    args.Append(std::move(result));
-
-    for (const scoped_refptr<const extensions::Extension>& extension :
-         ExtensionRegistry::Get(profile_)->enabled_extensions()) {
-      const std::string& extension_id = extension->id();
-      if (router->ExtensionHasEventListener(extension_id, event_name)) {
-        std::unique_ptr<base::ListValue> args_copy(args.DeepCopy());
-        // TODO(kalman): Have a histogram value for each pref type.
-        // This isn't so important for the current use case of these
-        // histograms, which is to track which event types are waking up event
-        // pages, or which are delivered to persistent background pages. Simply
-        // "a setting changed" is enough detail for that. However if we try to
-        // use these histograms for any fine-grained logic (like removing the
-        // string event name altogether), or if we discover this event is
-        // firing a lot and want to understand that better, then this will need
-        // to change.
-        events::HistogramValue histogram_value =
-            events::TYPES_PRIVATE_CHROME_DIRECT_SETTING_ON_CHANGE;
-        std::unique_ptr<Event> event(
-            new Event(histogram_value, event_name, std::move(args_copy)));
-        router->DispatchEventToExtension(extension_id, std::move(event));
-      }
-    }
-  }
-}
-
-}  // namespace chromedirectsetting
-}  // namespace extensions
diff --git a/chrome/browser/extensions/api/preference/chrome_direct_setting_api.h b/chrome/browser/extensions/api/preference/chrome_direct_setting_api.h
deleted file mode 100644
index 226cf99..0000000
--- a/chrome/browser/extensions/api/preference/chrome_direct_setting_api.h
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_EXTENSIONS_API_PREFERENCE_CHROME_DIRECT_SETTING_API_H__
-#define CHROME_BROWSER_EXTENSIONS_API_PREFERENCE_CHROME_DIRECT_SETTING_API_H__
-
-#include "base/macros.h"
-#include "components/prefs/pref_change_registrar.h"
-#include "extensions/browser/browser_context_keyed_api_factory.h"
-#include "extensions/browser/event_router.h"
-
-class Profile;
-
-namespace content {
-class BrowserContext;
-}
-
-namespace extensions {
-namespace chromedirectsetting {
-
-class ChromeDirectSettingAPI : public BrowserContextKeyedAPI,
-                               public EventRouter::Observer {
- public:
-  explicit ChromeDirectSettingAPI(content::BrowserContext* context);
-
-  ~ChromeDirectSettingAPI() override;
-
-  // KeyedService implementation.
-  void Shutdown() override;
-
-  // BrowserContextKeyedAPI implementation.
-  static BrowserContextKeyedAPIFactory<ChromeDirectSettingAPI>*
-      GetFactoryInstance();
-
-  // EventRouter::Observer implementation.
-  void OnListenerAdded(const EventListenerInfo& details) override;
-
-  // Returns true if the preference is on the whitelist.
-  bool IsPreferenceOnWhitelist(const std::string& pref_key);
-
-  // Convenience method to get the ChromeDirectSettingAPI for a profile.
-  static ChromeDirectSettingAPI* Get(content::BrowserContext* context);
-
- private:
-  friend class BrowserContextKeyedAPIFactory<ChromeDirectSettingAPI>;
-
-  // BrowserContextKeyedAPI implementation.
-  static const char* service_name();
-
-  void OnPrefChanged(PrefService* pref_service, const std::string& pref_key);
-
-  static const bool kServiceIsNULLWhileTesting = true;
-  static const bool kServiceRedirectedInIncognito = false;
-
-  PrefChangeRegistrar registrar_;
-  Profile* profile_;
-
-  DISALLOW_COPY_AND_ASSIGN(ChromeDirectSettingAPI);
-};
-
-}  // namespace chromedirectsetting
-}  // namespace extensions
-
-#endif  // CHROME_BROWSER_EXTENSIONS_API_PREFERENCE_CHROME_DIRECT_SETTING_API_H__
diff --git a/chrome/browser/extensions/api/preference/preferences_private_apitest.cc b/chrome/browser/extensions/api/preference/preferences_private_apitest.cc
new file mode 100644
index 0000000..0dd2f8c
--- /dev/null
+++ b/chrome/browser/extensions/api/preference/preferences_private_apitest.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 "chrome/browser/extensions/extension_apitest.h"
+#include "extensions/common/switches.h"
+
+namespace extensions {
+
+class PreferencesPrivateApiTest : public ExtensionApiTest {
+ public:
+  PreferencesPrivateApiTest() {}
+  ~PreferencesPrivateApiTest() override {}
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    ExtensionApiTest::SetUpCommandLine(command_line);
+    command_line->AppendSwitchASCII(switches::kWhitelistedExtensionID,
+                                    "cpfhkdbjfdgdebcjlifoldbijinjfifp");
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PreferencesPrivateApiTest);
+};
+
+IN_PROC_BROWSER_TEST_F(PreferencesPrivateApiTest, TestEasyUnlockEvent) {
+  ASSERT_TRUE(RunExtensionTest("preferences_private")) << message_;
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/browser_context_keyed_service_factories.cc b/chrome/browser/extensions/browser_context_keyed_service_factories.cc
index f8dc374..2403fc0f 100644
--- a/chrome/browser/extensions/browser_context_keyed_service_factories.cc
+++ b/chrome/browser/extensions/browser_context_keyed_service_factories.cc
@@ -25,7 +25,6 @@
 #include "chrome/browser/extensions/api/language_settings_private/language_settings_private_delegate_factory.h"
 #include "chrome/browser/extensions/api/omnibox/omnibox_api.h"
 #include "chrome/browser/extensions/api/passwords_private/passwords_private_event_router_factory.h"
-#include "chrome/browser/extensions/api/preference/chrome_direct_setting_api.h"
 #include "chrome/browser/extensions/api/preference/preference_api.h"
 #include "chrome/browser/extensions/api/processes/processes_api.h"
 #include "chrome/browser/extensions/api/screenlock_private/screenlock_private_api.h"
@@ -82,7 +81,6 @@
   extensions::BookmarksAPI::GetFactoryInstance();
   extensions::BookmarkManagerPrivateAPI::GetFactoryInstance();
   extensions::BrailleDisplayPrivateAPI::GetFactoryInstance();
-  extensions::chromedirectsetting::ChromeDirectSettingAPI::GetFactoryInstance();
   extensions::CommandService::GetFactoryInstance();
   extensions::ContentSettingsService::GetFactoryInstance();
   extensions::CookiesAPI::GetFactoryInstance();
diff --git a/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc b/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc
index a7904cf6..2c2d2fdb 100644
--- a/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc
+++ b/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc
@@ -861,12 +861,8 @@
     const base::FilePath& storage_partition_path,
     std::vector<std::unique_ptr<storage::FileSystemBackend>>*
         additional_backends) {
-  base::SequencedWorkerPool* pool = content::BrowserThread::GetBlockingPool();
-  auto sequence_token =
-      pool->GetNamedSequenceToken(MediaFileSystemBackend::kMediaTaskRunnerName);
-  additional_backends->push_back(base::MakeUnique<MediaFileSystemBackend>(
-      storage_partition_path,
-      pool->GetSequencedTaskRunner(sequence_token).get()));
+  additional_backends->push_back(
+      base::MakeUnique<MediaFileSystemBackend>(storage_partition_path));
 
   additional_backends->push_back(
       base::MakeUnique<sync_file_system::SyncFileSystemBackend>(
diff --git a/chrome/browser/extensions/chrome_extensions_browser_client.cc b/chrome/browser/extensions/chrome_extensions_browser_client.cc
index 2f1540e5..4398370d 100644
--- a/chrome/browser/extensions/chrome_extensions_browser_client.cc
+++ b/chrome/browser/extensions/chrome_extensions_browser_client.cc
@@ -16,7 +16,6 @@
 #include "chrome/browser/extensions/api/chrome_extensions_api_client.h"
 #include "chrome/browser/extensions/api/content_settings/content_settings_service.h"
 #include "chrome/browser/extensions/api/generated_api_registration.h"
-#include "chrome/browser/extensions/api/preference/chrome_direct_setting.h"
 #include "chrome/browser/extensions/api/preference/preference_api.h"
 #include "chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate.h"
 #include "chrome/browser/extensions/chrome_component_extension_resource_manager.h"
@@ -273,11 +272,6 @@
   registry->RegisterFunction<SetPreferenceFunction>();
   registry->RegisterFunction<ClearPreferenceFunction>();
 
-  // Direct Preference Access for Component Extensions.
-  registry->RegisterFunction<chromedirectsetting::GetDirectSettingFunction>();
-  registry->RegisterFunction<chromedirectsetting::SetDirectSettingFunction>();
-  registry->RegisterFunction<chromedirectsetting::ClearDirectSettingFunction>();
-
   // Generated APIs from lower-level modules.
   api::GeneratedFunctionRegistry::RegisterAll(registry);
 
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 5199b63..da560e19 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -2099,6 +2099,13 @@
     "If enabled, Chrome will draw the titlebar and caption buttons instead of "
     "deferring to Windows.";
 
+#if DCHECK_IS_ON() && defined(SYZYASAN)
+extern const char kSyzyAsanDcheckIsFatalName[] = "DCHECKs are fatal";
+extern const char kSyzyAsanDcheckIsFatalDescription[] =
+    "By default Chrome will evaluate DCHECKs in SyzyASAN builds, but only log "
+    "failed DCHECKs. If enabled, DCHECKs will crash the calling process.";
+#endif  // DCHECK_IS_ON() && defined(SYZYASAN)
+
 #endif  // defined(OS_WIN)
 
 // Mac -------------------------------------------------------------------------
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 6098994f..ecb001d 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_FLAG_DESCRIPTIONS_H_
 
 // Includes needed for macros allowing conditional compilation of some strings.
+#include "base/logging.h"
 #include "build/build_config.h"
 #include "build/buildflag.h"
 #include "chrome/common/features.h"
@@ -1279,6 +1280,11 @@
 extern const char kWindows10CustomTitlebarName[];
 extern const char kWindows10CustomTitlebarDescription[];
 
+#if DCHECK_IS_ON() && defined(SYZYASAN)
+extern const char kSyzyAsanDcheckIsFatalName[];
+extern const char kSyzyAsanDcheckIsFatalDescription[];
+#endif  // DCHECK_IS_ON() && defined(SYZYASAN)
+
 #endif  // defined(OS_WIN)
 
 // Mac ------------------------------------------------------------------------
diff --git a/chrome/browser/font_family_cache.h b/chrome/browser/font_family_cache.h
index 2961f37..9366134 100644
--- a/chrome/browser/font_family_cache.h
+++ b/chrome/browser/font_family_cache.h
@@ -25,6 +25,10 @@
 // relies on the assumption that each concatenation of map_name + '.' + script
 // is a unique string. It also relies on the assumption that the (const char*)
 // keys used in both inner and outer maps are compile time constants.
+// This class caches the strings necessary to update
+// "content::ScriptFontFamilyMap". This is necessary since Chrome attempts to
+// update content::ScriptFontFamilyMap 20000 times at startup. See
+// https://crbug.com/308095.
 class FontFamilyCache : public base::SupportsUserData::Data,
                         public content::NotificationObserver {
  public:
diff --git a/chrome/browser/media/webrtc/media_stream_devices_controller.cc b/chrome/browser/media/webrtc/media_stream_devices_controller.cc
index d39da60..272e5cbb8 100644
--- a/chrome/browser/media/webrtc/media_stream_devices_controller.cc
+++ b/chrome/browser/media/webrtc/media_stream_devices_controller.cc
@@ -394,6 +394,7 @@
     callback.Run(content::MediaStreamDevices(),
                  content::MEDIA_DEVICE_FAILED_DUE_TO_SHUTDOWN,
                  std::unique_ptr<content::MediaStreamUI>());
+    return;
   }
   content::WebContents* web_contents =
       content::WebContents::FromRenderFrameHost(rfh);
diff --git a/chrome/browser/media/webrtc/media_stream_devices_controller_browsertest.cc b/chrome/browser/media/webrtc/media_stream_devices_controller_browsertest.cc
index ae32f7f..071684c 100644
--- a/chrome/browser/media/webrtc/media_stream_devices_controller_browsertest.cc
+++ b/chrome/browser/media/webrtc/media_stream_devices_controller_browsertest.cc
@@ -865,6 +865,31 @@
   ASSERT_FALSE(CheckDevicesListContains(content::MEDIA_DEVICE_VIDEO_CAPTURE));
 }
 
+IN_PROC_BROWSER_TEST_P(MediaStreamDevicesControllerTest, WebContentsDestroyed) {
+  InitWithUrl(GURL("http://www.example.com"));
+
+  SetPromptResponseType(PermissionRequestManager::ACCEPT_ALL);
+
+  ResetPromptCounters();
+
+  content::MediaStreamRequest request =
+      CreateRequest(example_audio_id(), example_video_id());
+  // Simulate a destroyed RenderFrameHost.
+  request.render_frame_id = 0;
+  request.render_process_id = 0;
+
+  RequestPermissions(
+      nullptr, request,
+      base::Bind(&MediaStreamDevicesControllerTest::OnMediaStreamResponse,
+                 base::Unretained(this)));
+  ASSERT_EQ(0u, TotalPromptRequestCount());
+
+  ASSERT_EQ(content::MEDIA_DEVICE_FAILED_DUE_TO_SHUTDOWN,
+            media_stream_result());
+  ASSERT_FALSE(CheckDevicesListContains(content::MEDIA_DEVICE_AUDIO_CAPTURE));
+  ASSERT_FALSE(CheckDevicesListContains(content::MEDIA_DEVICE_VIDEO_CAPTURE));
+}
+
 // Request and block microphone and camera access with kill switch.
 IN_PROC_BROWSER_TEST_P(MediaStreamDevicesControllerTest,
                        RequestAndKillSwitchMicCam) {
diff --git a/chrome/browser/media_galleries/fileapi/file_path_watcher_util.cc b/chrome/browser/media_galleries/fileapi/file_path_watcher_util.cc
deleted file mode 100644
index 05ca742..0000000
--- a/chrome/browser/media_galleries/fileapi/file_path_watcher_util.cc
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/media_galleries/fileapi/file_path_watcher_util.h"
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h"
-#include "content/public/browser/browser_thread.h"
-
-namespace {
-
-// Bounces |path| and |error| to |callback| from the FILE thread to the media
-// task runner.
-void OnFilePathChangedOnFileThread(
-    const base::FilePathWatcher::Callback& callback,
-    const base::FilePath& path,
-    bool error) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
-  MediaFileSystemBackend::MediaTaskRunner()->PostTask(
-      FROM_HERE, base::Bind(callback, path, error));
-}
-
-// The watch has to be started on the FILE thread, and the callback called by
-// the FilePathWatcher also needs to run on the FILE thread.
-void StartFilePathWatchOnFileThread(
-    const base::FilePath& path,
-    const FileWatchStartedCallback& watch_started_callback,
-    const base::FilePathWatcher::Callback& path_changed_callback) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
-  // The watcher is created on the FILE thread because it is very difficult
-  // to safely pass an already-created file watcher to a different thread.
-  MediaFilePathWatcherUniquePtr watcher(new base::FilePathWatcher);
-  bool success = watcher->Watch(
-      path,
-      false /* recursive */,
-      base::Bind(&OnFilePathChangedOnFileThread, path_changed_callback));
-  if (!success)
-    LOG(ERROR) << "Adding watch for " << path.value() << " failed";
-  MediaFileSystemBackend::MediaTaskRunner()->PostTask(
-      FROM_HERE, base::Bind(watch_started_callback, base::Passed(&watcher)));
-}
-
-}  // namespace
-
-void StartFilePathWatchOnMediaTaskRunner(
-    const base::FilePath& path,
-    const FileWatchStartedCallback& watch_started_callback,
-    const base::FilePathWatcher::Callback& path_changed_callback) {
-  MediaFileSystemBackend::AssertCurrentlyOnMediaSequence();
-  content::BrowserThread::PostTask(content::BrowserThread::FILE,
-                                   FROM_HERE,
-                                   base::Bind(&StartFilePathWatchOnFileThread,
-                                              path,
-                                              watch_started_callback,
-                                              path_changed_callback));
-}
diff --git a/chrome/browser/media_galleries/fileapi/file_path_watcher_util.h b/chrome/browser/media_galleries/fileapi/file_path_watcher_util.h
deleted file mode 100644
index 2fe080e..0000000
--- a/chrome/browser/media_galleries/fileapi/file_path_watcher_util.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_FILE_PATH_WATCHER_UTIL_H_
-#define CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_FILE_PATH_WATCHER_UTIL_H_
-
-#include <memory>
-
-#include "base/callback_forward.h"
-#include "base/files/file_path.h"
-#include "base/files/file_path_watcher.h"
-#include "content/public/browser/browser_thread.h"
-
-using MediaFilePathWatcherUniquePtr =
-    std::unique_ptr<base::FilePathWatcher,
-                    content::BrowserThread::DeleteOnFileThread>;
-using FileWatchStartedCallback =
-    base::Callback<void(MediaFilePathWatcherUniquePtr watcher)>;
-
-// Called on the MediaTaskRunner to begin a file watch.
-// |watch_started_callback| is responsible for taking ownership of the
-// file watcher upon start. All callbacks are run on the MediaTaskRunner.
-void StartFilePathWatchOnMediaTaskRunner(
-    const base::FilePath& path,
-    const FileWatchStartedCallback& watch_started_callback,
-    const base::FilePathWatcher::Callback& path_changed_callback);
-
-#endif  // CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_FILE_PATH_WATCHER_UTIL_H_
diff --git a/chrome/browser/media_galleries/fileapi/iapps_data_provider.cc b/chrome/browser/media_galleries/fileapi/iapps_data_provider.cc
index 9404431d..ac8ca31d 100644
--- a/chrome/browser/media_galleries/fileapi/iapps_data_provider.cc
+++ b/chrome/browser/media_galleries/fileapi/iapps_data_provider.cc
@@ -30,12 +30,9 @@
   MediaFileSystemBackend::AssertCurrentlyOnMediaSequence();
   DCHECK(!library_path_.empty());
 
-  StartFilePathWatchOnMediaTaskRunner(
-      library_path_,
-      base::Bind(&IAppsDataProvider::OnLibraryWatchStarted,
-                 weak_factory_.GetWeakPtr()),
-      base::Bind(&IAppsDataProvider::OnLibraryChanged,
-                 weak_factory_.GetWeakPtr()));
+  library_watcher_.Watch(library_path_, false /* recursive */,
+                         base::Bind(&IAppsDataProvider::OnLibraryChanged,
+                                    weak_factory_.GetWeakPtr()));
 }
 
 IAppsDataProvider::~IAppsDataProvider() {}
@@ -64,12 +61,6 @@
   return library_path_;
 }
 
-void IAppsDataProvider::OnLibraryWatchStarted(
-    MediaFilePathWatcherUniquePtr library_watcher) {
-  MediaFileSystemBackend::AssertCurrentlyOnMediaSequence();
-  library_watcher_ = std::move(library_watcher);
-}
-
 void IAppsDataProvider::OnLibraryChanged(const base::FilePath& path,
                                          bool error) {
   MediaFileSystemBackend::AssertCurrentlyOnMediaSequence();
diff --git a/chrome/browser/media_galleries/fileapi/iapps_data_provider.h b/chrome/browser/media_galleries/fileapi/iapps_data_provider.h
index b35ac00..32d7f1c 100644
--- a/chrome/browser/media_galleries/fileapi/iapps_data_provider.h
+++ b/chrome/browser/media_galleries/fileapi/iapps_data_provider.h
@@ -15,7 +15,6 @@
 #include "base/files/file_path_watcher.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "chrome/browser/media_galleries/fileapi/file_path_watcher_util.h"
 
 namespace iapps {
 
@@ -52,10 +51,6 @@
   virtual void OnLibraryChanged(const base::FilePath& path, bool error);
 
  private:
-  // Called when the FilePathWatcher for |library_path_| has tried to add an
-  // watch.
-  void OnLibraryWatchStarted(MediaFilePathWatcherUniquePtr library_watcher);
-
   // Path to the library XML file.
   const base::FilePath library_path_;
 
@@ -67,7 +62,7 @@
   bool is_valid_;
 
   // A watcher on the library xml file.
-  MediaFilePathWatcherUniquePtr library_watcher_;
+  base::FilePathWatcher library_watcher_;
 
   base::WeakPtrFactory<IAppsDataProvider> weak_factory_;
 
diff --git a/chrome/browser/media_galleries/fileapi/itunes_data_provider.cc b/chrome/browser/media_galleries/fileapi/itunes_data_provider.cc
index 7d7995c..cf8155f7 100644
--- a/chrome/browser/media_galleries/fileapi/itunes_data_provider.cc
+++ b/chrome/browser/media_galleries/fileapi/itunes_data_provider.cc
@@ -17,7 +17,6 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/threading/thread_restrictions.h"
-#include "chrome/browser/media_galleries/fileapi/file_path_watcher_util.h"
 #include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h"
 #include "chrome/browser/media_galleries/imported_media_gallery_registry.h"
 #include "chrome/common/media_galleries/itunes_library.h"
diff --git a/chrome/browser/media_galleries/fileapi/itunes_file_util_unittest.cc b/chrome/browser/media_galleries/fileapi/itunes_file_util_unittest.cc
index e13f3d5..78a5b91 100644
--- a/chrome/browser/media_galleries/fileapi/itunes_file_util_unittest.cc
+++ b/chrome/browser/media_galleries/fileapi/itunes_file_util_unittest.cc
@@ -15,18 +15,16 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "base/time/time.h"
 #include "chrome/browser/media_galleries/fileapi/itunes_data_provider.h"
 #include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h"
 #include "chrome/browser/media_galleries/fileapi/media_path_filter.h"
 #include "chrome/browser/media_galleries/imported_media_gallery_registry.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/test/test_browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "content/public/test/test_utils.h"
 #include "storage/browser/fileapi/async_file_util.h"
 #include "storage/browser/fileapi/external_mount_points.h"
 #include "storage/browser/fileapi/file_system_context.h"
@@ -124,9 +122,7 @@
  public:
   TestMediaFileSystemBackend(const base::FilePath& profile_path,
                              ITunesFileUtil* itunes_file_util)
-      : MediaFileSystemBackend(
-            profile_path,
-            MediaFileSystemBackend::MediaTaskRunner().get()),
+      : MediaFileSystemBackend(profile_path),
         test_file_util_(itunes_file_util) {}
 
   storage::AsyncFileUtil* GetAsyncFileUtil(
@@ -144,8 +140,10 @@
 class ItunesFileUtilTest : public testing::Test {
  public:
   ItunesFileUtilTest()
-      : io_thread_(content::BrowserThread::IO, &message_loop_) {
-  }
+      : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
+        itunes_data_provider_(nullptr,
+                              base::OnTaskRunnerDeleter(
+                                  MediaFileSystemBackend::MediaTaskRunner())) {}
 
   void SetUpDataProvider() {
     ASSERT_TRUE(fake_library_dir_.CreateUniqueTempDir());
@@ -164,17 +162,12 @@
     scoped_refptr<storage::SpecialStoragePolicy> storage_policy =
         new content::MockSpecialStoragePolicy();
 
-    // Initialize fake ItunesDataProvider on media task runner thread.
+    // Initialize fake ItunesDataProvider on media task runner.
     MediaFileSystemBackend::MediaTaskRunner()->PostTask(
         FROM_HERE,
         base::Bind(&ItunesFileUtilTest::SetUpDataProvider,
                    base::Unretained(this)));
-    base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
-                              base::WaitableEvent::InitialState::NOT_SIGNALED);
-    MediaFileSystemBackend::MediaTaskRunner()->PostTask(
-        FROM_HERE,
-        base::Bind(&base::WaitableEvent::Signal, base::Unretained(&event)));
-    event.Wait();
+    content::RunAllBlockingPoolTasksUntilIdle();
 
     media_path_filter_.reset(new MediaPathFilter());
     std::vector<std::unique_ptr<storage::FileSystemBackend>>
@@ -185,8 +178,10 @@
                                itunes_data_provider_.get())));
 
     file_system_context_ = new storage::FileSystemContext(
-        base::ThreadTaskRunnerHandle::Get().get(),
-        base::ThreadTaskRunnerHandle::Get().get(),
+        content::BrowserThread::GetTaskRunnerForThread(
+            content::BrowserThread::IO)
+            .get(),
+        base::SequencedTaskRunnerHandle::Get().get(),
         storage::ExternalMountPoints::CreateRefCounted().get(),
         storage_policy.get(), NULL, std::move(additional_providers),
         std::vector<storage::URLRequestAutoMountHandler>(),
@@ -226,16 +221,16 @@
     return itunes_data_provider_.get();
   }
 
- private:
-  base::MessageLoop message_loop_;
-  content::TestBrowserThread io_thread_;
+  content::TestBrowserThreadBundle thread_bundle_;
 
+ private:
   base::ScopedTempDir profile_dir_;
   base::ScopedTempDir fake_library_dir_;
 
   scoped_refptr<storage::FileSystemContext> file_system_context_;
   std::unique_ptr<MediaPathFilter> media_path_filter_;
-  std::unique_ptr<TestITunesDataProvider> itunes_data_provider_;
+  std::unique_ptr<TestITunesDataProvider, base::OnTaskRunnerDeleter>
+      itunes_data_provider_;
 
   DISALLOW_COPY_AND_ASSIGN(ItunesFileUtilTest);
 };
diff --git a/chrome/browser/media_galleries/fileapi/media_file_system_backend.cc b/chrome/browser/media_galleries/fileapi/media_file_system_backend.cc
index 055ad07..bd8c3c0 100644
--- a/chrome/browser/media_galleries/fileapi/media_file_system_backend.cc
+++ b/chrome/browser/media_galleries/fileapi/media_file_system_backend.cc
@@ -16,7 +16,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/threading/sequenced_worker_pool.h"
+#include "base/task_scheduler/lazy_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
@@ -61,10 +61,11 @@
 
 const char kMediaGalleryMountPrefix[] = "media_galleries-";
 
-#if DCHECK_IS_ON()
-base::LazyInstance<base::SequenceChecker>::Leaky g_media_sequence_checker =
-    LAZY_INSTANCE_INITIALIZER;
-#endif
+base::LazySequencedTaskRunner g_media_task_runner =
+    LAZY_SEQUENCED_TASK_RUNNER_INITIALIZER(
+        base::TaskTraits(base::MayBlock(),
+                         base::TaskPriority::USER_VISIBLE,
+                         base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN));
 
 void OnPreferencesInit(
     const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter,
@@ -129,14 +130,9 @@
 
 }  // namespace
 
-const char MediaFileSystemBackend::kMediaTaskRunnerName[] =
-    "media-task-runner";
-
 MediaFileSystemBackend::MediaFileSystemBackend(
-    const base::FilePath& profile_path,
-    base::SequencedTaskRunner* media_task_runner)
+    const base::FilePath& profile_path)
     : profile_path_(profile_path),
-      media_task_runner_(media_task_runner),
       media_path_filter_(new MediaPathFilter),
       media_copy_or_move_file_validator_factory_(new MediaFileValidatorFactory),
       native_media_file_util_(new NativeMediaFileUtil(media_path_filter_.get()))
@@ -162,17 +158,14 @@
 // static
 void MediaFileSystemBackend::AssertCurrentlyOnMediaSequence() {
 #if DCHECK_IS_ON()
-  DCHECK(g_media_sequence_checker.Get().CalledOnValidSequence());
+  DCHECK(g_media_task_runner.Get()->RunsTasksInCurrentSequence());
 #endif
 }
 
 // static
 scoped_refptr<base::SequencedTaskRunner>
 MediaFileSystemBackend::MediaTaskRunner() {
-  base::SequencedWorkerPool* pool = content::BrowserThread::GetBlockingPool();
-  base::SequencedWorkerPool::SequenceToken media_sequence_token =
-      pool->GetNamedSequenceToken(kMediaTaskRunnerName);
-  return pool->GetSequencedTaskRunner(media_sequence_token);
+  return g_media_task_runner.Get();
 }
 
 // static
@@ -317,7 +310,7 @@
     base::File::Error* error_code) const {
   std::unique_ptr<storage::FileSystemOperationContext> operation_context(
       new storage::FileSystemOperationContext(context,
-                                              media_task_runner_.get()));
+                                              MediaTaskRunner().get()));
   return storage::FileSystemOperation::Create(url, context,
                                               std::move(operation_context));
 }
diff --git a/chrome/browser/media_galleries/fileapi/media_file_system_backend.h b/chrome/browser/media_galleries/fileapi/media_file_system_backend.h
index 5f073a6..fe65412 100644
--- a/chrome/browser/media_galleries/fileapi/media_file_system_backend.h
+++ b/chrome/browser/media_galleries/fileapi/media_file_system_backend.h
@@ -36,11 +36,7 @@
 
 class MediaFileSystemBackend : public storage::FileSystemBackend {
  public:
-  static const char kMediaTaskRunnerName[];
-
-  MediaFileSystemBackend(
-      const base::FilePath& profile_path,
-      base::SequencedTaskRunner* media_task_runner);
+  explicit MediaFileSystemBackend(const base::FilePath& profile_path);
   ~MediaFileSystemBackend() override;
 
   // Asserts that the current task is sequenced with any other task that calls
@@ -103,8 +99,6 @@
   // Store the profile path. We need this to create temporary snapshot files.
   const base::FilePath profile_path_;
 
-  scoped_refptr<base::SequencedTaskRunner> media_task_runner_;
-
   std::unique_ptr<MediaPathFilter> media_path_filter_;
   std::unique_ptr<storage::CopyOrMoveFileValidatorFactory>
       media_copy_or_move_file_validator_factory_;
diff --git a/chrome/browser/media_galleries/fileapi/media_file_validator_browsertest.cc b/chrome/browser/media_galleries/fileapi/media_file_validator_browsertest.cc
index 7b2723e..908095bf 100644
--- a/chrome/browser/media_galleries/fileapi/media_file_validator_browsertest.cc
+++ b/chrome/browser/media_galleries/fileapi/media_file_validator_browsertest.cc
@@ -128,8 +128,8 @@
     additional_providers.push_back(
         base::MakeUnique<content::TestFileSystemBackend>(
             base::ThreadTaskRunnerHandle::Get().get(), src_path));
-    additional_providers.push_back(base::MakeUnique<MediaFileSystemBackend>(
-        base, base::ThreadTaskRunnerHandle::Get().get()));
+    additional_providers.push_back(
+        base::MakeUnique<MediaFileSystemBackend>(base));
     file_system_context_ =
         content::CreateFileSystemContextWithAdditionalProvidersForTesting(
             NULL, std::move(additional_providers), base);
diff --git a/chrome/browser/media_galleries/fileapi/native_media_file_util_unittest.cc b/chrome/browser/media_galleries/fileapi/native_media_file_util_unittest.cc
index c5a25bfea..4e5a892 100644
--- a/chrome/browser/media_galleries/fileapi/native_media_file_util_unittest.cc
+++ b/chrome/browser/media_galleries/fileapi/native_media_file_util_unittest.cc
@@ -15,13 +15,13 @@
 #include "base/format_macros.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "base/time/time.h"
 #include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h"
-#include "content/public/test/test_browser_thread.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "content/public/test/test_utils.h"
 #include "storage/browser/blob/shareable_file_reference.h"
 #include "storage/browser/fileapi/external_mount_points.h"
 #include "storage/browser/fileapi/file_system_backend.h"
@@ -118,9 +118,7 @@
 
 class NativeMediaFileUtilTest : public testing::Test {
  public:
-  NativeMediaFileUtilTest()
-      : io_thread_(content::BrowserThread::IO, &message_loop_) {
-  }
+  NativeMediaFileUtilTest() {}
 
   void SetUp() override {
     ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
@@ -131,12 +129,14 @@
 
     std::vector<std::unique_ptr<storage::FileSystemBackend>>
         additional_providers;
-    additional_providers.push_back(base::MakeUnique<MediaFileSystemBackend>(
-        data_dir_.GetPath(), base::ThreadTaskRunnerHandle::Get().get()));
+    additional_providers.push_back(
+        base::MakeUnique<MediaFileSystemBackend>(data_dir_.GetPath()));
 
     file_system_context_ = new storage::FileSystemContext(
-        base::ThreadTaskRunnerHandle::Get().get(),
-        base::ThreadTaskRunnerHandle::Get().get(),
+        content::BrowserThread::GetTaskRunnerForThread(
+            content::BrowserThread::IO)
+            .get(),
+        base::SequencedTaskRunnerHandle::Get().get(),
         storage::ExternalMountPoints::CreateRefCounted().get(),
         storage_policy.get(), NULL, std::move(additional_providers),
         std::vector<storage::URLRequestAutoMountHandler>(), data_dir_.GetPath(),
@@ -190,10 +190,9 @@
     return file_system_context_->operation_runner();
   }
 
- private:
-  base::MessageLoop message_loop_;
-  content::TestBrowserThread io_thread_;
+  content::TestBrowserThreadBundle thread_bundle_;
 
+ private:
   base::ScopedTempDir data_dir_;
   scoped_refptr<storage::FileSystemContext> file_system_context_;
 
@@ -224,7 +223,7 @@
       operation_runner()->FileExists(
           url, base::Bind(&ExpectEqHelper, test_name, expectation));
     }
-    base::RunLoop().RunUntilIdle();
+    content::RunAllBlockingPoolTasksUntilIdle();
   }
 }
 
@@ -238,7 +237,7 @@
   bool completed = false;
   operation_runner()->ReadDirectory(
       url, base::BindRepeating(&DidReadDirectory, &content, &completed));
-  base::RunLoop().RunUntilIdle();
+  content::RunAllBlockingPoolTasksUntilIdle();
   EXPECT_TRUE(completed);
   EXPECT_EQ(6u, content.size());
 
@@ -271,7 +270,7 @@
             url, false, false,
             base::Bind(&ExpectEqHelper, test_name, expectation));
       }
-      base::RunLoop().RunUntilIdle();
+      content::RunAllBlockingPoolTasksUntilIdle();
     }
   }
 }
@@ -311,7 +310,7 @@
           storage::FileSystemOperation::ERROR_BEHAVIOR_ABORT,
           storage::FileSystemOperationRunner::CopyProgressCallback(),
           base::Bind(&ExpectEqHelper, test_name, expectation));
-      base::RunLoop().RunUntilIdle();
+      content::RunAllBlockingPoolTasksUntilIdle();
     }
   }
 }
@@ -377,7 +376,7 @@
           storage::FileSystemOperation::ERROR_BEHAVIOR_ABORT,
           storage::FileSystemOperationRunner::CopyProgressCallback(),
           base::Bind(&ExpectEqHelper, test_name, expectation));
-      base::RunLoop().RunUntilIdle();
+      content::RunAllBlockingPoolTasksUntilIdle();
     }
   }
 }
@@ -417,7 +416,7 @@
           dest_url,
           storage::FileSystemOperation::OPTION_NONE,
           base::Bind(&ExpectEqHelper, test_name, expectation));
-      base::RunLoop().RunUntilIdle();
+      content::RunAllBlockingPoolTasksUntilIdle();
     }
   }
 }
@@ -484,7 +483,7 @@
           url,
           storage::FileSystemOperation::OPTION_NONE,
           base::Bind(&ExpectEqHelper, test_name, expectation));
-      base::RunLoop().RunUntilIdle();
+      content::RunAllBlockingPoolTasksUntilIdle();
     }
   }
 }
@@ -512,7 +511,7 @@
           url, storage::FileSystemOperation::GET_METADATA_FIELD_IS_DIRECTORY,
           base::Bind(&ExpectMetadataEqHelper, test_name, expectation,
                      kFilteringTestCases[i].is_directory));
-      base::RunLoop().RunUntilIdle();
+      content::RunAllBlockingPoolTasksUntilIdle();
     }
   }
 }
@@ -540,7 +539,7 @@
       }
       operation_runner()->RemoveFile(
           url, base::Bind(&ExpectEqHelper, test_name, expectation));
-      base::RunLoop().RunUntilIdle();
+      content::RunAllBlockingPoolTasksUntilIdle();
     }
   }
 }
@@ -572,7 +571,7 @@
     error = base::File::FILE_ERROR_FAILED;
     operation_runner()->CreateSnapshotFile(url,
         base::Bind(CreateSnapshotCallback, &error));
-    base::RunLoop().RunUntilIdle();
+    content::RunAllBlockingPoolTasksUntilIdle();
     ASSERT_EQ(expected_error, error);
   }
 }
diff --git a/chrome/browser/media_galleries/fileapi/picasa_data_provider.cc b/chrome/browser/media_galleries/fileapi/picasa_data_provider.cc
index 866789d..d67ada9 100644
--- a/chrome/browser/media_galleries/fileapi/picasa_data_provider.cc
+++ b/chrome/browser/media_galleries/fileapi/picasa_data_provider.cc
@@ -42,10 +42,9 @@
       weak_factory_(this) {
   MediaFileSystemBackend::AssertCurrentlyOnMediaSequence();
 
-  StartFilePathWatchOnMediaTaskRunner(
+  temp_dir_watcher_.Watch(
       database_path_.DirName().AppendASCII(kPicasaTempDirName),
-      base::Bind(&PicasaDataProvider::OnTempDirWatchStarted,
-                 weak_factory_.GetWeakPtr()),
+      false /* recursive */,
       base::Bind(&PicasaDataProvider::OnTempDirChanged,
                  weak_factory_.GetWeakPtr()));
 }
@@ -125,12 +124,6 @@
   DoRefreshIfNecessary();
 }
 
-void PicasaDataProvider::OnTempDirWatchStarted(
-    MediaFilePathWatcherUniquePtr temp_dir_watcher) {
-  MediaFileSystemBackend::AssertCurrentlyOnMediaSequence();
-  temp_dir_watcher_ = std::move(temp_dir_watcher);
-}
-
 void PicasaDataProvider::OnTempDirChanged(const base::FilePath& temp_dir_path,
                                           bool error) {
   MediaFileSystemBackend::AssertCurrentlyOnMediaSequence();
diff --git a/chrome/browser/media_galleries/fileapi/picasa_data_provider.h b/chrome/browser/media_galleries/fileapi/picasa_data_provider.h
index 798d91d..c1b8aea 100644
--- a/chrome/browser/media_galleries/fileapi/picasa_data_provider.h
+++ b/chrome/browser/media_galleries/fileapi/picasa_data_provider.h
@@ -18,7 +18,6 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
-#include "chrome/browser/media_galleries/fileapi/file_path_watcher_util.h"
 #include "chrome/common/media_galleries/picasa_types.h"
 
 namespace picasa {
@@ -66,10 +65,6 @@
   friend class PicasaFileUtilTest;
   friend class TestPicasaDataProvider;
 
-  // Called when the FilePathWatcher for Picasa's temp directory has started.
-  virtual void OnTempDirWatchStarted(
-      MediaFilePathWatcherUniquePtr temp_dir_watcher);
-
   // Called when Picasa's temp directory has changed. Virtual for testing.
   virtual void OnTempDirChanged(const base::FilePath& temp_dir_path,
                                 bool error);
@@ -110,7 +105,7 @@
 
   // We watch the temp dir, as we can't detect database file modifications on
   // Mac, but we are able to detect creation and deletion of temporary files.
-  MediaFilePathWatcherUniquePtr temp_dir_watcher_;
+  base::FilePathWatcher temp_dir_watcher_;
 
   base::WeakPtrFactory<PicasaDataProvider> weak_factory_;
 
diff --git a/chrome/browser/media_galleries/fileapi/picasa_data_provider_browsertest.cc b/chrome/browser/media_galleries/fileapi/picasa_data_provider_browsertest.cc
index 4bd7be3..5c31546 100644
--- a/chrome/browser/media_galleries/fileapi/picasa_data_provider_browsertest.cc
+++ b/chrome/browser/media_galleries/fileapi/picasa_data_provider_browsertest.cc
@@ -102,22 +102,10 @@
 class TestPicasaDataProvider : public PicasaDataProvider {
  public:
   explicit TestPicasaDataProvider(const base::FilePath& database_path)
-      : PicasaDataProvider(database_path),
-        file_watch_request_returned_(false)  {
-  }
+      : PicasaDataProvider(database_path) {}
 
   ~TestPicasaDataProvider() override {}
 
-  // |ready_callback| called with true if and when the file watch is started
-  // successfully. If the file watch fails, it's called with false.
-  void EnsureFileWatchStartedForTesting(const ReadyCallback& ready_callback) {
-    if (!file_watch_request_returned_) {
-      file_watch_started_callbacks_.push_back(ready_callback);
-      return;
-    }
-    ready_callback.Run(temp_dir_watcher_.get() != NULL);
-  }
-
   // Simulates the actual writing process of moving all the database files
   // from the temporary directory to the database directory in a loop.
   void MoveTempFilesToDatabase() {
@@ -156,24 +144,6 @@
   }
 
  private:
-  void OnTempDirWatchStarted(
-      MediaFilePathWatcherUniquePtr temp_dir_watcher) override {
-    PicasaDataProvider::OnTempDirWatchStarted(std::move(temp_dir_watcher));
-
-    file_watch_request_returned_ = true;
-    for (std::vector<ReadyCallback>::const_iterator it =
-             file_watch_started_callbacks_.begin();
-         it != file_watch_started_callbacks_.end();
-         ++it) {
-      it->Run(temp_dir_watcher_.get() != NULL);
-    }
-    file_watch_started_callbacks_.clear();
-  }
-
-  // Used for test that utilizes file watch
-  bool file_watch_request_returned_;
-  std::vector<ReadyCallback> file_watch_started_callbacks_;
-
   base::Closure invalidate_callback_;
 };
 
@@ -452,14 +422,6 @@
  protected:
   virtual void ListCallback(bool parse_success) {
     ASSERT_FALSE(parse_success);
-    data_provider()->EnsureFileWatchStartedForTesting(
-        base::Bind(&PicasaDataProviderFileWatcherInvalidateTest::
-                       OnPicasaTempDirWatchStarted,
-                   base::Unretained(this)));
-  }
-
-  void OnPicasaTempDirWatchStarted(bool file_watch_successful) {
-    ASSERT_TRUE(file_watch_successful);
 
     // Validate the list after the file move triggers an invalidate.
     data_provider()->SetInvalidateCallback(base::Bind(
diff --git a/chrome/browser/media_galleries/fileapi/picasa_file_util_unittest.cc b/chrome/browser/media_galleries/fileapi/picasa_file_util_unittest.cc
index 227f7ca..27fe044 100644
--- a/chrome/browser/media_galleries/fileapi/picasa_file_util_unittest.cc
+++ b/chrome/browser/media_galleries/fileapi/picasa_file_util_unittest.cc
@@ -20,11 +20,9 @@
 #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/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "base/time/time.h"
 #include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h"
 #include "chrome/browser/media_galleries/fileapi/media_path_filter.h"
@@ -33,7 +31,7 @@
 #include "chrome/common/media_galleries/picasa_types.h"
 #include "chrome/common/media_galleries/pmp_constants.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/test/test_browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "storage/browser/blob/shareable_file_reference.h"
 #include "storage/browser/fileapi/async_file_util.h"
 #include "storage/browser/fileapi/external_mount_points.h"
@@ -212,8 +210,7 @@
  public:
   TestMediaFileSystemBackend(const base::FilePath& profile_path,
                              PicasaFileUtil* picasa_file_util)
-      : MediaFileSystemBackend(profile_path,
-                               MediaFileSystemBackend::MediaTaskRunner().get()),
+      : MediaFileSystemBackend(profile_path),
         test_file_util_(picasa_file_util) {}
 
   storage::AsyncFileUtil* GetAsyncFileUtil(
@@ -231,11 +228,14 @@
 class PicasaFileUtilTest : public testing::Test {
  public:
   PicasaFileUtilTest()
-      : io_thread_(content::BrowserThread::IO, &message_loop_) {
-  }
+      : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
+        picasa_data_provider_(nullptr,
+                              base::OnTaskRunnerDeleter(
+                                  MediaFileSystemBackend::MediaTaskRunner())) {}
 
   void SetUp() override {
     ASSERT_TRUE(profile_dir_.CreateUniqueTempDir());
+
     ImportedMediaGalleryRegistry::GetInstance()->Initialize();
 
     scoped_refptr<storage::SpecialStoragePolicy> storage_policy =
@@ -254,27 +254,21 @@
                                picasa_data_provider_.get())));
 
     file_system_context_ = new storage::FileSystemContext(
-        base::ThreadTaskRunnerHandle::Get().get(),
-        base::ThreadTaskRunnerHandle::Get().get(),
+        content::BrowserThread::GetTaskRunnerForThread(
+            content::BrowserThread::IO)
+            .get(),
+        base::SequencedTaskRunnerHandle::Get().get(),
         storage::ExternalMountPoints::CreateRefCounted().get(),
         storage_policy.get(), NULL, std::move(additional_providers),
         std::vector<storage::URLRequestAutoMountHandler>(),
         profile_dir_.GetPath(), content::CreateAllowFileAccessOptions());
   }
 
-  void TearDown() override {
-    SynchronouslyRunOnMediaTaskRunner(
-        base::Bind(&PicasaFileUtilTest::TearDownOnMediaTaskRunner,
-                   base::Unretained(this)));
-  }
-
  protected:
   void SetUpOnMediaTaskRunner() {
-    picasa_data_provider_.reset(new PicasaDataProvider(base::FilePath()));
-  }
-
-  void TearDownOnMediaTaskRunner() {
-    picasa_data_provider_.reset();
+    ASSERT_TRUE(database_dir_.CreateUniqueTempDir());
+    picasa_data_provider_.reset(
+        new PicasaDataProvider(database_dir_.GetPath()));
   }
 
   // |test_folders| must be in alphabetical order for easy verification
@@ -374,14 +368,15 @@
     return file_system_context_;
   }
 
- private:
-  base::MessageLoop message_loop_;
-  content::TestBrowserThread io_thread_;
+  content::TestBrowserThreadBundle thread_bundle_;
 
+ private:
   base::ScopedTempDir profile_dir_;
+  base::ScopedTempDir database_dir_;
 
   scoped_refptr<storage::FileSystemContext> file_system_context_;
-  std::unique_ptr<PicasaDataProvider> picasa_data_provider_;
+  std::unique_ptr<PicasaDataProvider, base::OnTaskRunnerDeleter>
+      picasa_data_provider_;
   std::unique_ptr<MediaPathFilter> media_path_filter_;
 
   DISALLOW_COPY_AND_ASSIGN(PicasaFileUtilTest);
diff --git a/chrome/browser/metrics/android_metrics_provider.cc b/chrome/browser/metrics/android_metrics_provider.cc
index ce3c2a32..0e01c89 100644
--- a/chrome/browser/metrics/android_metrics_provider.cc
+++ b/chrome/browser/metrics/android_metrics_provider.cc
@@ -6,27 +6,10 @@
 
 #include "base/metrics/histogram_macros.h"
 #include "base/sys_info.h"
-#include "base/values.h"
 #include "chrome/browser/android/feature_utilities.h"
-#include "chrome/common/pref_names.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/pref_service.h"
-#include "components/prefs/scoped_user_pref_update.h"
 
 namespace {
 
-// Increments a particular entry in the ListValue.
-void IncrementListValue(base::Value* counts, int index) {
-  counts->GetList()[index] = base::Value(counts->GetList()[index].GetInt() + 1);
-}
-
-// Takes an int corresponding to a Type and returns the corresponding flag.
-int GetActivityFlag(int type_id) {
-  ActivityTypeIds::Type type = ActivityTypeIds::GetActivityType(type_id);
-  DCHECK_LT(type, ActivityTypeIds::ACTIVITY_MAX_VALUE);
-  return (1 << type);
-}
-
 void EmitLowRamDeviceHistogram() {
   UMA_HISTOGRAM_BOOLEAN("MemoryAndroid.LowRamDevice",
                         base::SysInfo::IsLowEndDevice());
@@ -34,17 +17,13 @@
 
 }  // namespace
 
-AndroidMetricsProvider::AndroidMetricsProvider(PrefService* local_state)
-    : local_state_(local_state) {
-  LogStabilityToPrefs();
-}
+AndroidMetricsProvider::AndroidMetricsProvider() {}
 
 AndroidMetricsProvider::~AndroidMetricsProvider() {
 }
 
 void AndroidMetricsProvider::ProvidePreviousSessionData(
     metrics::ChromeUserMetricsExtension* uma_proto) {
-  ConvertStabilityPrefsToHistograms();
   // The low-ram device status is unlikely to change between browser restarts.
   // Hence, it's safe and useful to attach this status to a previous session
   // log.
@@ -53,7 +32,6 @@
 
 void AndroidMetricsProvider::ProvideCurrentSessionData(
     metrics::ChromeUserMetricsExtension* uma_proto) {
-  ConvertStabilityPrefsToHistograms();
   EmitLowRamDeviceHistogram();
   UMA_HISTOGRAM_ENUMERATION(
       "CustomTabs.Visible",
@@ -63,107 +41,3 @@
       "Android.MultiWindowMode.Active",
       chrome::android::GetIsInMultiWindowModeValue());
 }
-
-void AndroidMetricsProvider::OnForegroundActivityChanged(
-    ActivityTypeIds::Type type) {
-  DCHECK_LT(type, ActivityTypeIds::ACTIVITY_MAX_VALUE);
-
-  if (type == local_state_->GetInteger(prefs::kStabilityForegroundActivityType))
-    return;
-
-  // Record that the Activity is now in the foreground.
-  local_state_->SetInteger(prefs::kStabilityForegroundActivityType, type);
-
-  // Record that the Activity was launched this sesaion.
-  // The pref stores a set of flags ORed together, where each set flag
-  // corresponds to a launched Activity type.
-  int launched =
-      local_state_->GetInteger(prefs::kStabilityLaunchedActivityFlags);
-  if (type != ActivityTypeIds::ACTIVITY_NONE) {
-    launched |= GetActivityFlag(type);
-    local_state_->SetInteger(prefs::kStabilityLaunchedActivityFlags, launched);
-  }
-
-  local_state_->CommitPendingWrite();
-}
-
-// static
-void AndroidMetricsProvider::RegisterPrefs(PrefRegistrySimple* registry) {
-  registry->RegisterIntegerPref(prefs::kStabilityForegroundActivityType,
-                                ActivityTypeIds::ACTIVITY_NONE);
-  registry->RegisterIntegerPref(prefs::kStabilityLaunchedActivityFlags, 0);
-  registry->RegisterListPref(prefs::kStabilityLaunchedActivityCounts);
-  registry->RegisterListPref(prefs::kStabilityCrashedActivityCounts);
-}
-
-void AndroidMetricsProvider::LogStabilityToPrefs() {
-  // Track which Activities were launched by the user.
-  // A 'launch' is defined as starting the Activity at least once during a
-  // UMA session.  Multiple launches are counted only once since it is possible
-  // for users to hop between Activities (e.g. entering and leaving Settings).
-  const int launched =
-      local_state_->GetInteger(prefs::kStabilityLaunchedActivityFlags);
-  ListPrefUpdate update_launches(local_state_,
-                                 prefs::kStabilityLaunchedActivityCounts);
-  base::ListValue* launch_counts = update_launches.Get();
-  for (int activity_type = ActivityTypeIds::ACTIVITY_NONE;
-       activity_type < ActivityTypeIds::ACTIVITY_MAX_VALUE;
-       ++activity_type) {
-    if (launched & GetActivityFlag(activity_type))
-      IncrementListValue(launch_counts, activity_type);
-  }
-  local_state_->SetInteger(prefs::kStabilityLaunchedActivityFlags, 0);
-
-  // Track any Activities that were in the foreground when Chrome died.
-  // These Activities failed to be recorded as leaving the foreground, so Chrome
-  // couldn't have ended the UMA session cleanly.  Record them as crashing.
-  const int foreground =
-      local_state_->GetInteger(prefs::kStabilityForegroundActivityType);
-  if (foreground != ActivityTypeIds::ACTIVITY_NONE) {
-    ListPrefUpdate update_crashes(local_state_,
-                                  prefs::kStabilityCrashedActivityCounts);
-    base::ListValue* crash_counts = update_crashes.Get();
-    IncrementListValue(crash_counts, foreground);
-    local_state_->SetInteger(prefs::kStabilityForegroundActivityType,
-                             ActivityTypeIds::ACTIVITY_NONE);
-  }
-
-  local_state_->CommitPendingWrite();
-}
-
-void AndroidMetricsProvider::ConvertStabilityPrefsToHistograms() {
-  ListPrefUpdate launch_updater(local_state_,
-                                prefs::kStabilityLaunchedActivityCounts);
-  ListPrefUpdate crash_updater(local_state_,
-                               prefs::kStabilityCrashedActivityCounts);
-
-  base::ListValue* launch_counts = launch_updater.Get();
-  base::ListValue* crash_counts = crash_updater.Get();
-
-  for (int activity_type = ActivityTypeIds::ACTIVITY_NONE;
-       activity_type < ActivityTypeIds::ACTIVITY_MAX_VALUE;
-       ++activity_type) {
-    int launch_count = 0;
-    int crash_count = 0;
-
-    launch_counts->GetInteger(activity_type, &launch_count);
-    crash_counts->GetInteger(activity_type, &crash_count);
-
-    for (int count = 0; count < launch_count; ++count) {
-      UMA_STABILITY_HISTOGRAM_ENUMERATION(
-          "Chrome.Android.Activity.LaunchCounts",
-          static_cast<ActivityTypeIds::Type>(activity_type),
-          ActivityTypeIds::ACTIVITY_MAX_VALUE);
-    }
-
-    for (int count = 0; count < crash_count; ++count) {
-      UMA_STABILITY_HISTOGRAM_ENUMERATION(
-          "Chrome.Android.Activity.CrashCounts",
-          static_cast<ActivityTypeIds::Type>(activity_type),
-          ActivityTypeIds::ACTIVITY_MAX_VALUE);
-    }
-  }
-
-  launch_counts->Clear();
-  crash_counts->Clear();
-}
diff --git a/chrome/browser/metrics/android_metrics_provider.h b/chrome/browser/metrics/android_metrics_provider.h
index 0302af3f..18fd3b1 100644
--- a/chrome/browser/metrics/android_metrics_provider.h
+++ b/chrome/browser/metrics/android_metrics_provider.h
@@ -6,12 +6,8 @@
 #define CHROME_BROWSER_METRICS_ANDROID_METRICS_PROVIDER_H_
 
 #include "base/macros.h"
-#include "chrome/browser/android/activity_type_ids.h"
 #include "components/metrics/metrics_provider.h"
 
-class PrefService;
-class PrefRegistrySimple;
-
 namespace metrics {
 class ChromeUserMetricsExtension;
 }
@@ -19,8 +15,7 @@
 // AndroidMetricsProvider provides Android-specific stability metrics.
 class AndroidMetricsProvider : public metrics::MetricsProvider {
  public:
-  // Creates the AndroidMetricsProvider with the given |local_state|.
-  explicit AndroidMetricsProvider(PrefService* local_state);
+  AndroidMetricsProvider();
   ~AndroidMetricsProvider() override;
 
   // metrics::MetricsProvider:
@@ -29,23 +24,7 @@
   void ProvideCurrentSessionData(
       metrics::ChromeUserMetricsExtension* uma_proto) override;
 
-  // Called when the Activity that the user interacts with is swapped out.
-  // TODO(asvitkine): Expose a way for Android code to actually invoke this.
-  void OnForegroundActivityChanged(ActivityTypeIds::Type type);
-
-  // Registers local state prefs used by this class.
-  static void RegisterPrefs(PrefRegistrySimple* registry);
-
  private:
-  // Called to log launch and crash stats to preferences.
-  void LogStabilityToPrefs();
-
-  // Converts crash stats stored in the preferences into histograms.
-  void ConvertStabilityPrefsToHistograms();
-
-  // Weak pointer to the local state prefs store.
-  PrefService* local_state_;
-
   DISALLOW_COPY_AND_ASSIGN(AndroidMetricsProvider);
 };
 
diff --git a/chrome/browser/metrics/chrome_metrics_service_client.cc b/chrome/browser/metrics/chrome_metrics_service_client.cc
index e2260c4b..546bb1d 100644
--- a/chrome/browser/metrics/chrome_metrics_service_client.cc
+++ b/chrome/browser/metrics/chrome_metrics_service_client.cc
@@ -379,10 +379,6 @@
 
   metrics::RegisterMetricsReportingStatePrefs(registry);
 
-#if defined(OS_ANDROID)
-  AndroidMetricsProvider::RegisterPrefs(registry);
-#endif  // defined(OS_ANDROID)
-
 #if BUILDFLAG(ENABLE_PLUGINS)
   PluginMetricsProvider::RegisterPrefs(registry);
 #endif  // BUILDFLAG(ENABLE_PLUGINS)
@@ -600,8 +596,7 @@
 
 #if defined(OS_ANDROID)
   metrics_service_->RegisterMetricsProvider(
-      std::unique_ptr<metrics::MetricsProvider>(
-          new AndroidMetricsProvider(local_state)));
+      std::unique_ptr<metrics::MetricsProvider>(new AndroidMetricsProvider()));
   metrics_service_->RegisterMetricsProvider(
       std::unique_ptr<metrics::MetricsProvider>(new PageLoadMetricsProvider()));
 #endif  // defined(OS_ANDROID)
diff --git a/chrome/browser/metrics/perf/perf_provider_chromeos.cc b/chrome/browser/metrics/perf/perf_provider_chromeos.cc
index 363a584..b3318584 100644
--- a/chrome/browser/metrics/perf/perf_provider_chromeos.cc
+++ b/chrome/browser/metrics/perf/perf_provider_chromeos.cc
@@ -22,8 +22,10 @@
 #include "base/sys_info.h"
 #include "chrome/browser/metrics/perf/windowed_incognito_observer.h"
 #include "chrome/browser/ui/browser_list.h"
+#include "chrome/common/channel_info.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "components/variations/variations_associated_data.h"
+#include "components/version_info/channel.h"
 #include "content/public/browser/browser_thread.h"
 
 namespace metrics {
@@ -78,6 +80,35 @@
       base::RandGenerator(max.InMicroseconds()));
 }
 
+// Returns a TimeDelta profile duration based on the current chrome channel.
+base::TimeDelta ProfileDuration() {
+  switch (chrome::GetChannel()) {
+    case version_info::Channel::CANARY:
+    case version_info::Channel::DEV:
+    case version_info::Channel::BETA:
+      return base::TimeDelta::FromSeconds(4);
+    case version_info::Channel::STABLE:
+    case version_info::Channel::UNKNOWN:
+    default:
+      return base::TimeDelta::FromSeconds(2);
+  }
+}
+
+// Returns a TimeDelta interval duration for periodic collection based on the
+// current chrome channel.
+base::TimeDelta PeriodicCollectionInterval() {
+  switch (chrome::GetChannel()) {
+    case version_info::Channel::CANARY:
+    case version_info::Channel::DEV:
+    case version_info::Channel::BETA:
+      return base::TimeDelta::FromMinutes(90);
+    case version_info::Channel::STABLE:
+    case version_info::Channel::UNKNOWN:
+    default:
+      return base::TimeDelta::FromMinutes(180);
+  }
+}
+
 // Gets parameter named by |key| from the map. If it is present and is an
 // integer, stores the result in |out| and return true. Otherwise return false.
 bool GetInt64Param(const std::map<std::string, std::string>& params,
@@ -284,16 +315,18 @@
 }  // namespace internal
 
 PerfProvider::CollectionParams::CollectionParams()
-    : CollectionParams(
-        base::TimeDelta::FromSeconds(2) /* collection_duration */,
-        base::TimeDelta::FromHours(3) /* periodic_interval */,
-        PerfProvider::CollectionParams::TriggerParams( /* resume_from_suspend */
-            10 /* sampling_factor */,
-            base::TimeDelta::FromSeconds(5)) /* max_collection_delay */,
-        PerfProvider::CollectionParams::TriggerParams( /* restore_session */
-            10 /* sampling_factor */,
-            base::TimeDelta::FromSeconds(10)) /* max_collection_delay */) {
-}
+    : CollectionParams(ProfileDuration() /* collection_duration */,
+                       PeriodicCollectionInterval() /* periodic_interval */,
+                       PerfProvider::CollectionParams::
+                           TriggerParams(/* resume_from_suspend */
+                                         10 /* sampling_factor */,
+                                         base::TimeDelta::FromSeconds(
+                                             5)) /* max_collection_delay */,
+                       PerfProvider::CollectionParams::
+                           TriggerParams(/* restore_session */
+                                         10 /* sampling_factor */,
+                                         base::TimeDelta::FromSeconds(
+                                             10)) /* max_collection_delay */) {}
 
 PerfProvider::CollectionParams::CollectionParams(
     base::TimeDelta collection_duration,
diff --git a/chrome/browser/offline_pages/android/evaluation/offline_page_evaluation_bridge.cc b/chrome/browser/offline_pages/android/evaluation/offline_page_evaluation_bridge.cc
index 150f193d..87fe57ac 100644
--- a/chrome/browser/offline_pages/android/evaluation/offline_page_evaluation_bridge.cc
+++ b/chrome/browser/offline_pages/android/evaluation/offline_page_evaluation_bridge.cc
@@ -35,6 +35,7 @@
 #include "components/offline_pages/core/downloads/download_notifying_observer.h"
 #include "components/offline_pages/core/offline_page_item.h"
 #include "components/offline_pages/core/offline_page_model.h"
+#include "components/offline_pages/core/offline_pages_ukm_reporter.h"
 #include "content/public/browser/browser_context.h"
 #include "jni/OfflinePageEvaluationBridge_jni.h"
 
@@ -149,10 +150,13 @@
   net::NetworkQualityEstimator::NetworkQualityProvider*
       network_quality_estimator =
           UINetworkQualityEstimatorServiceFactory::GetForProfile(profile);
+  std::unique_ptr<OfflinePagesUkmReporter> ukm_reporter(
+      new OfflinePagesUkmReporter());
   std::unique_ptr<RequestCoordinator> request_coordinator =
       base::MakeUnique<RequestCoordinator>(
           std::move(policy), std::move(offliner), std::move(queue),
-          std::move(scheduler), network_quality_estimator);
+          std::move(scheduler), network_quality_estimator,
+          std::move(ukm_reporter));
   request_coordinator->SetInternalStartProcessingCallbackForTest(
       base::Bind(&android::EvaluationTestScheduler::ImmediateScheduleCallback,
                  base::Unretained(scheduler.get())));
diff --git a/chrome/browser/offline_pages/android/request_coordinator_factory.cc b/chrome/browser/offline_pages/android/request_coordinator_factory.cc
index 124b72bd..7833364 100644
--- a/chrome/browser/offline_pages/android/request_coordinator_factory.cc
+++ b/chrome/browser/offline_pages/android/request_coordinator_factory.cc
@@ -31,6 +31,7 @@
 #include "components/offline_pages/core/background/scheduler.h"
 #include "components/offline_pages/core/downloads/download_notifying_observer.h"
 #include "components/offline_pages/core/offline_page_feature.h"
+#include "components/offline_pages/core/offline_pages_ukm_reporter.h"
 #include "net/nqe/network_quality_estimator.h"
 
 namespace offline_pages {
@@ -86,9 +87,11 @@
   net::NetworkQualityEstimator::NetworkQualityProvider*
       network_quality_estimator =
           UINetworkQualityEstimatorServiceFactory::GetForProfile(profile);
+  std::unique_ptr<OfflinePagesUkmReporter> ukm_reporter(
+      new OfflinePagesUkmReporter());
   RequestCoordinator* request_coordinator = new RequestCoordinator(
       std::move(policy), std::move(offliner), std::move(queue),
-      std::move(scheduler), network_quality_estimator);
+      std::move(scheduler), network_quality_estimator, std::move(ukm_reporter));
 
   DownloadNotifyingObserver::CreateAndStartObserving(
       request_coordinator,
diff --git a/chrome/browser/offline_pages/prefetch/prefetch_importer_impl.cc b/chrome/browser/offline_pages/prefetch/prefetch_importer_impl.cc
index 342af30..92a89274 100644
--- a/chrome/browser/offline_pages/prefetch/prefetch_importer_impl.cc
+++ b/chrome/browser/offline_pages/prefetch/prefetch_importer_impl.cc
@@ -8,6 +8,7 @@
 #include "base/files/file_util.h"
 #include "base/guid.h"
 #include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
@@ -24,6 +25,38 @@
 
 const base::FilePath::CharType kMHTMLExtension[] = FILE_PATH_LITERAL("mhtml");
 
+// Mirror of the OfflinePrefetchPageImportResult histogram enum so existing
+// entries can never be removed and new ones must be appended with new values.
+enum class PageImportResult {
+  SUCCESS = 0,
+  UNKNOWN = 1,
+  FILE_MOVE_ERROR = 2,
+  OFFLINE_STORE_FAILURE = 3,
+  OFFLINE_ITEM_ALREADY_EXISTS = 4,
+  // Always leave this item last. Update if the actual last item changes.
+  MAX = OFFLINE_ITEM_ALREADY_EXISTS
+};
+
+PageImportResult FromAddPageResult(AddPageResult result) {
+  switch (result) {
+    case AddPageResult::SUCCESS:
+      return PageImportResult::SUCCESS;
+    case AddPageResult::STORE_FAILURE:
+      return PageImportResult::OFFLINE_STORE_FAILURE;
+    case AddPageResult::ALREADY_EXISTS:
+      return PageImportResult::OFFLINE_ITEM_ALREADY_EXISTS;
+    case AddPageResult::RESULT_COUNT:
+      NOTREACHED();
+  }
+  NOTREACHED();
+  return PageImportResult::UNKNOWN;
+}
+
+void ReportPageImportResult(PageImportResult result) {
+  UMA_HISTOGRAM_ENUMERATION("OfflinePages.Prefetching.OfflinePageImportResult",
+                            result, PageImportResult::MAX);
+}
+
 void MoveFile(const base::FilePath& src_path,
               const base::FilePath& dest_path,
               base::TaskRunner* task_runner,
@@ -89,6 +122,7 @@
 void PrefetchImporterImpl::OnMoveFileDone(const OfflinePageItem& offline_page,
                                           bool success) {
   if (!success) {
+    ReportPageImportResult(PageImportResult::FILE_MOVE_ERROR);
     NotifyImportCompleted(OfflinePageModel::kInvalidOfflineId, false);
     return;
   }
@@ -104,6 +138,7 @@
 
 void PrefetchImporterImpl::OnPageAdded(AddPageResult result,
                                        int64_t offline_id) {
+  ReportPageImportResult(FromAddPageResult(result));
   NotifyImportCompleted(offline_id, result == AddPageResult::SUCCESS);
 }
 
diff --git a/chrome/browser/offline_pages/test_request_coordinator_builder.cc b/chrome/browser/offline_pages/test_request_coordinator_builder.cc
index 3b5f521..280beb02 100644
--- a/chrome/browser/offline_pages/test_request_coordinator_builder.cc
+++ b/chrome/browser/offline_pages/test_request_coordinator_builder.cc
@@ -13,6 +13,7 @@
 #include "components/offline_pages/core/background/request_queue.h"
 #include "components/offline_pages/core/background/request_queue_in_memory_store.h"
 #include "components/offline_pages/core/background/scheduler_stub.h"
+#include "components/offline_pages/core/offline_pages_ukm_reporter_stub.h"
 #include "content/public/browser/browser_context.h"
 
 namespace offline_pages {
@@ -36,9 +37,13 @@
   NetworkQualityProviderStub* network_quality_provider =
       NetworkQualityProviderStub::GetUserData(context);
 
+  std::unique_ptr<OfflinePagesUkmReporter> ukm_reporter_stub(
+      new OfflinePagesUkmReporterStub());
+
   return std::unique_ptr<RequestCoordinator>(new RequestCoordinator(
       std::move(policy), std::move(offliner), std::move(queue),
-      std::move(scheduler_stub), network_quality_provider));
+      std::move(scheduler_stub), network_quality_provider,
+      std::move(ukm_reporter_stub)));
 }
 
 }  // namespace offline_pages
diff --git a/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc b/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc
index 2601d55c..01f2e17 100644
--- a/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc
+++ b/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc
@@ -618,6 +618,8 @@
 
     if (error)
       return;
+  } else if (!committed_load_) {
+    RecordInternalError(ERR_SUBFRAME_IPC_WITH_NO_RELEVANT_LOAD);
   }
 
   if (committed_load_) {
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
index 85ab0fe..a8db1f1d 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
+++ b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
@@ -486,6 +486,24 @@
   histogram_tester_.ExpectTotalCount(internal::kHistogramFirstPaint, 1);
 }
 
+IN_PROC_BROWSER_TEST_F(PageLoadMetricsBrowserTest, PaintInDynamicChildFrame) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  auto waiter = CreatePageLoadMetricsWaiter();
+  waiter->AddPageExpectation(TimingField::FIRST_LAYOUT);
+  waiter->AddPageExpectation(TimingField::LOAD_EVENT);
+  waiter->AddSubFrameExpectation(TimingField::FIRST_PAINT);
+  waiter->AddSubFrameExpectation(TimingField::FIRST_CONTENTFUL_PAINT);
+  ui_test_utils::NavigateToURL(
+      browser(),
+      embedded_test_server()->GetURL("/page_load_metrics/dynamic_iframe.html"));
+  waiter->Wait();
+
+  histogram_tester_.ExpectTotalCount(internal::kHistogramFirstLayout, 1);
+  histogram_tester_.ExpectTotalCount(internal::kHistogramLoad, 1);
+  histogram_tester_.ExpectTotalCount(internal::kHistogramFirstPaint, 1);
+}
+
 IN_PROC_BROWSER_TEST_F(PageLoadMetricsBrowserTest, PaintInMultipleChildFrames) {
   ASSERT_TRUE(embedded_test_server()->Start());
 
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_update_dispatcher.cc b/chrome/browser/page_load_metrics/page_load_metrics_update_dispatcher.cc
index ba774ba4..0b3f940 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_update_dispatcher.cc
+++ b/chrome/browser/page_load_metrics/page_load_metrics_update_dispatcher.cc
@@ -313,7 +313,6 @@
     content::NavigationHandle* navigation_handle,
     PageLoadMetricsEmbedderInterface* embedder_interface)
     : client_(client),
-      embedder_interface_(embedder_interface),
       timer_(embedder_interface->CreateTimer()),
       navigation_start_(navigation_handle->NavigationStart()),
       current_merged_page_timing_(CreatePageLoadTiming()),
@@ -358,12 +357,6 @@
   subframe_navigation_start_offset_.erase(
       navigation_handle->GetFrameTreeNodeId());
 
-  BrowserPageTrackDecider decider(embedder_interface_,
-                                  navigation_handle->GetWebContents(),
-                                  navigation_handle);
-  if (!decider.ShouldTrack())
-    return;
-
   if (navigation_start_ > navigation_handle->NavigationStart()) {
     RecordInternalError(ERR_SUBFRAME_NAVIGATION_START_BEFORE_MAIN_FRAME);
     return;
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_update_dispatcher.h b/chrome/browser/page_load_metrics/page_load_metrics_update_dispatcher.h
index da8a4b2..03666769 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_update_dispatcher.h
+++ b/chrome/browser/page_load_metrics/page_load_metrics_update_dispatcher.h
@@ -137,9 +137,6 @@
   // The client is guaranteed to outlive this object.
   Client* const client_;
 
-  // Interface to chrome features. Must outlive the class.
-  PageLoadMetricsEmbedderInterface* const embedder_interface_;
-
   std::unique_ptr<base::Timer> timer_;
 
   // Time the navigation for this page load was initiated.
diff --git a/chrome/browser/page_load_metrics/page_load_tracker.h b/chrome/browser/page_load_metrics/page_load_tracker.h
index a0f192e..f3063b07 100644
--- a/chrome/browser/page_load_metrics/page_load_tracker.h
+++ b/chrome/browser/page_load_metrics/page_load_tracker.h
@@ -131,6 +131,11 @@
   // navigation start of the main frame.
   ERR_SUBFRAME_NAVIGATION_START_BEFORE_MAIN_FRAME,
 
+  // We received an IPC from a subframe when we weren't tracking a committed
+  // load. We expect this error to happen, and track it so we can understand how
+  // frequently this case is encountered.
+  ERR_SUBFRAME_IPC_WITH_NO_RELEVANT_LOAD,
+
   // Add values before this final count.
   ERR_LAST_ENTRY,
 };
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc
index b99df4b..bc90c00 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -215,7 +215,10 @@
   // The password manager is disabled while VR (virtual reality) is being used,
   // as the use of conventional UI elements might harm the user experience in
   // VR.
-  is_enabled = is_enabled && !vr::VrTabHelper::IsInVr(web_contents());
+  if (vr::VrTabHelper::IsInVr(web_contents())) {
+    is_enabled = false;
+    vr::VrTabHelper::UISuppressed(vr::UiSuppressedElement::kPasswordManager);
+  }
 
   if (log_manager_->IsLoggingActive()) {
     password_manager::BrowserSavePasswordProgressLogger logger(
diff --git a/chrome/browser/permissions/permission_manager.cc b/chrome/browser/permissions/permission_manager.cc
index aca56ad..19c6834 100644
--- a/chrome/browser/permissions/permission_manager.cc
+++ b/chrome/browser/permissions/permission_manager.cc
@@ -10,6 +10,7 @@
 #include "base/callback.h"
 #include "base/memory/ptr_util.h"
 #include "build/build_config.h"
+#include "chrome/browser/accessibility/accessibility_permission_context.h"
 #include "chrome/browser/background_sync/background_sync_permission_context.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/generic_sensor/sensor_permission_context.h"
@@ -107,6 +108,8 @@
       return CONTENT_SETTINGS_TYPE_PLUGINS;
     case PermissionType::SENSORS:
       return CONTENT_SETTINGS_TYPE_SENSORS;
+    case PermissionType::ACCESSIBILITY_EVENTS:
+      return CONTENT_SETTINGS_TYPE_ACCESSIBILITY_EVENTS;
     case PermissionType::NUM:
       // This will hit the NOTREACHED below.
       break;
@@ -289,6 +292,8 @@
 #endif
   permission_contexts_[CONTENT_SETTINGS_TYPE_SENSORS] =
       base::MakeUnique<SensorPermissionContext>(profile);
+  permission_contexts_[CONTENT_SETTINGS_TYPE_ACCESSIBILITY_EVENTS] =
+      base::MakeUnique<AccessibilityPermissionContext>(profile);
 }
 
 PermissionManager::~PermissionManager() {
diff --git a/chrome/browser/permissions/permission_request.h b/chrome/browser/permissions/permission_request.h
index ffaeb50..e02392f 100644
--- a/chrome/browser/permissions/permission_request.h
+++ b/chrome/browser/permissions/permission_request.h
@@ -37,6 +37,7 @@
   PERMISSION_FLASH,
   PERMISSION_MEDIASTREAM_MIC,
   PERMISSION_MEDIASTREAM_CAMERA,
+  PERMISSION_ACCESSIBILITY_EVENTS,
   // NUM must be the last value in the enum.
   NUM
 };
diff --git a/chrome/browser/permissions/permission_request_impl.cc b/chrome/browser/permissions/permission_request_impl.cc
index a2588b3..fe4efccd 100644
--- a/chrome/browser/permissions/permission_request_impl.cc
+++ b/chrome/browser/permissions/permission_request_impl.cc
@@ -68,6 +68,8 @@
       return IDR_ANDROID_INFOBAR_MEDIA_STREAM_MIC;
     case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA:
       return IDR_ANDROID_INFOBAR_MEDIA_STREAM_CAMERA;
+    case CONTENT_SETTINGS_TYPE_ACCESSIBILITY_EVENTS:
+      return IDR_ANDROID_INFOBAR_ACCESSIBILITY_EVENTS;
     default:
       NOTREACHED();
       return IDR_ANDROID_INFOBAR_WARNING;
@@ -92,6 +94,8 @@
       return vector_icons::kMicrophoneIcon;
     case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA:
       return vector_icons::kVideocamIcon;
+    case CONTENT_SETTINGS_TYPE_ACCESSIBILITY_EVENTS:
+      return vector_icons::kAccessibilityIcon;
     default:
       NOTREACHED();
       return kExtensionIcon;
@@ -122,6 +126,9 @@
     case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA:
       message_id = IDS_MEDIA_CAPTURE_VIDEO_ONLY;
       break;
+    case CONTENT_SETTINGS_TYPE_ACCESSIBILITY_EVENTS:
+      message_id = IDS_ACCESSIBILITY_EVENTS_INFOBAR_QUESTION;
+      break;
     default:
       NOTREACHED();
       return base::string16();
@@ -160,6 +167,9 @@
     case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA:
       message_id = IDS_MEDIA_CAPTURE_VIDEO_ONLY_PERMISSION_FRAGMENT;
       break;
+    case CONTENT_SETTINGS_TYPE_ACCESSIBILITY_EVENTS:
+      message_id = IDS_ACCESSIBILITY_EVENTS_PERMISSION_FRAGMENT;
+      break;
     default:
       NOTREACHED();
       return base::string16();
diff --git a/chrome/browser/permissions/permission_util.cc b/chrome/browser/permissions/permission_util.cc
index 86ffa28..a128c5c 100644
--- a/chrome/browser/permissions/permission_util.cc
+++ b/chrome/browser/permissions/permission_util.cc
@@ -45,6 +45,8 @@
       return "Flash";
     case CONTENT_SETTINGS_TYPE_SENSORS:
       return "Sensors";
+    case CONTENT_SETTINGS_TYPE_ACCESSIBILITY_EVENTS:
+      return "AccessibilityEvents";
     default:
       break;
   }
@@ -77,6 +79,8 @@
       return "FLASH";
     case CONTENT_SETTINGS_TYPE_SENSORS:
       return "SENSORS";
+    case CONTENT_SETTINGS_TYPE_ACCESSIBILITY_EVENTS:
+      return "ACCESSIBILITY_EVENTS";
     default:
       break;
   }
@@ -102,6 +106,8 @@
       return PermissionRequestType::PERMISSION_MEDIASTREAM_MIC;
     case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA:
       return PermissionRequestType::PERMISSION_MEDIASTREAM_CAMERA;
+    case CONTENT_SETTINGS_TYPE_ACCESSIBILITY_EVENTS:
+      return PermissionRequestType::PERMISSION_ACCESSIBILITY_EVENTS;
     default:
       NOTREACHED();
       return PermissionRequestType::UNKNOWN;
@@ -141,6 +147,8 @@
 #endif
   } else if (type == CONTENT_SETTINGS_TYPE_SENSORS) {
     *out = PermissionType::SENSORS;
+  } else if (type == CONTENT_SETTINGS_TYPE_ACCESSIBILITY_EVENTS) {
+    *out = PermissionType::ACCESSIBILITY_EVENTS;
   } else {
     return false;
   }
@@ -169,6 +177,7 @@
     case CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER:
 #endif
     case CONTENT_SETTINGS_TYPE_SENSORS:
+    case CONTENT_SETTINGS_TYPE_ACCESSIBILITY_EVENTS:
       return true;
     default:
       return false;
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 35aa2e2..6e4e5b8 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -313,6 +313,18 @@
 // Preferences files added here 2/2017.
 constexpr char kDistroDict[] = "distribution";
 
+#if defined(OS_ANDROID)
+// Deprecated 8/2017.
+const char kStabilityForegroundActivityType[] =
+    "user_experience_metrics.stability.current_foreground_activity_type";
+const char kStabilityLaunchedActivityFlags[] =
+    "user_experience_metrics.stability.launched_activity_flags";
+const char kStabilityLaunchedActivityCounts[] =
+    "user_experience_metrics.stability.launched_activity_counts";
+const char kStabilityCrashedActivityCounts[] =
+    "user_experience_metrics.stability.crashed_activity_counts";
+#endif  // defined(OS_ANDROID)
+
 }  // namespace
 
 namespace chrome {
@@ -361,6 +373,12 @@
 
 #if defined(OS_ANDROID)
   ::android::RegisterPrefs(registry);
+
+  // Obsolete activity prefs. See MigrateObsoleteBrowserPrefs().
+  registry->RegisterIntegerPref(kStabilityForegroundActivityType, 0);
+  registry->RegisterIntegerPref(kStabilityLaunchedActivityFlags, 0);
+  registry->RegisterListPref(kStabilityLaunchedActivityCounts);
+  registry->RegisterListPref(kStabilityCrashedActivityCounts);
 #endif
 
 #if !defined(OS_ANDROID)
@@ -700,6 +718,14 @@
   local_state->ClearPref(prefs::kTouchscreenEnabled);
   local_state->ClearPref(prefs::kTouchpadEnabled);
 #endif  // defined(OS_CHROMEOS)
+
+#if defined(OS_ANDROID)
+  // Added 8/2017.
+  local_state->ClearPref(kStabilityForegroundActivityType);
+  local_state->ClearPref(kStabilityLaunchedActivityFlags);
+  local_state->ClearPref(kStabilityLaunchedActivityCounts);
+  local_state->ClearPref(kStabilityCrashedActivityCounts);
+#endif  // defined(OS_ANDROID)
 }
 
 // This method should be periodically pruned of year+ old migrations.
diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc
index 1872574..460098e 100644
--- a/chrome/browser/profiles/profile_manager.cc
+++ b/chrome/browser/profiles/profile_manager.cc
@@ -1588,16 +1588,12 @@
     bool has_entry = storage.GetProfileAttributesWithPath(profile->GetPath(),
                                                           &entry);
     if (has_entry) {
-#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
-      bool was_authenticated_status = entry->IsAuthenticated();
-#endif
       // The ProfileAttributesStorage's info must match the Signin Manager.
       entry->SetAuthInfo(account_info.gaia, username);
 #if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
       // Sign out if force-sign-in policy is enabled and profile is not signed
       // in.
-      if (signin_util::IsForceSigninEnabled() && was_authenticated_status &&
-          !entry->IsAuthenticated()) {
+      if (signin_util::IsForceSigninEnabled() && !entry->IsAuthenticated()) {
         BrowserThread::PostTask(
             BrowserThread::UI, FROM_HERE,
             base::BindOnce(&SignOut,
diff --git a/chrome/browser/resource_coordinator/background_tab_navigation_throttle.cc b/chrome/browser/resource_coordinator/background_tab_navigation_throttle.cc
index 25a2e43..484ab3f4 100644
--- a/chrome/browser/resource_coordinator/background_tab_navigation_throttle.cc
+++ b/chrome/browser/resource_coordinator/background_tab_navigation_throttle.cc
@@ -20,7 +20,7 @@
 std::unique_ptr<BackgroundTabNavigationThrottle>
 BackgroundTabNavigationThrottle::MaybeCreateThrottleFor(
     content::NavigationHandle* navigation_handle) {
-  if (!base::FeatureList::IsEnabled(features::kStaggeredBackgroundTabOpen))
+  if (!base::FeatureList::IsEnabled(features::kStaggeredBackgroundTabOpening))
     return nullptr;
 
   // Only consider main frames because this is to delay tabs.
diff --git a/chrome/browser/resource_coordinator/background_tab_navigation_throttle_unittest.cc b/chrome/browser/resource_coordinator/background_tab_navigation_throttle_unittest.cc
index dba97a5c..7e95c3a5 100644
--- a/chrome/browser/resource_coordinator/background_tab_navigation_throttle_unittest.cc
+++ b/chrome/browser/resource_coordinator/background_tab_navigation_throttle_unittest.cc
@@ -50,7 +50,7 @@
 
     if (enable_feature_) {
       scoped_feature_list_.InitAndEnableFeature(
-          features::kStaggeredBackgroundTabOpen);
+          features::kStaggeredBackgroundTabOpening);
     }
 
     ChromeRenderViewHostTestHarness::SetUp();
diff --git a/chrome/browser/resource_coordinator/tab_manager.cc b/chrome/browser/resource_coordinator/tab_manager.cc
index 002e503..8d5c8df 100644
--- a/chrome/browser/resource_coordinator/tab_manager.cc
+++ b/chrome/browser/resource_coordinator/tab_manager.cc
@@ -598,23 +598,11 @@
   return GetWebContentsData(web_contents)->is_restored_in_foreground();
 }
 
-bool TabManager::IsLoadingBackgroundTabs() const {
-  if (IsSessionRestoreLoadingTabs())
+bool TabManager::IsInBackgroundTabOpeningSession() const {
+  if (background_tab_loading_mode_ != BackgroundTabLoadingMode::kStaggered)
     return false;
 
-  if (!pending_navigations_.empty())
-    return true;
-
-  // Excluding session restore above leaves only background opening tabs in
-  // |loading_contents_|. As long as they still remain in background, we are
-  // still loading background tabs, even after we emptied our pending navigation
-  // list.
-  for (const content::WebContents* tab : loading_contents_) {
-    if (!tab->IsVisible())
-      return true;
-  }
-
-  return false;
+  return !(pending_navigations_.empty() && loading_contents_.empty());
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -922,6 +910,21 @@
   return null_contents;
 }
 
+void TabManager::PauseBackgroundTabOpeningIfNeeded() {
+  if (IsInBackgroundTabOpeningSession())
+    stats_collector_->OnBackgroundTabOpeningSessionEnded();
+
+  background_tab_loading_mode_ = BackgroundTabLoadingMode::kPaused;
+}
+
+void TabManager::ResumeBackgroundTabOpeningIfNeeded() {
+  background_tab_loading_mode_ = BackgroundTabLoadingMode::kStaggered;
+  LoadNextBackgroundTabIfNeeded();
+
+  if (IsInBackgroundTabOpeningSession())
+    stats_collector_->OnBackgroundTabOpeningSessionStarted();
+}
+
 void TabManager::OnMemoryPressure(
     base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
   // If Chrome is shutting down, do not do anything.
@@ -930,14 +933,13 @@
 
   switch (memory_pressure_level) {
     case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
-      background_tab_loading_mode_ = BackgroundTabLoadingMode::kStaggered;
-      LoadNextBackgroundTabIfNeeded();
+      ResumeBackgroundTabOpeningIfNeeded();
       break;
     case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
-      background_tab_loading_mode_ = BackgroundTabLoadingMode::kPaused;
+      PauseBackgroundTabOpeningIfNeeded();
       break;
     case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
-      background_tab_loading_mode_ = BackgroundTabLoadingMode::kPaused;
+      PauseBackgroundTabOpeningIfNeeded();
       LogMemoryAndDiscardTab(kUrgentShutdown);
       break;
     default:
@@ -1122,18 +1124,30 @@
 
 content::NavigationThrottle::ThrottleCheckResult
 TabManager::MaybeThrottleNavigation(BackgroundTabNavigationThrottle* throttle) {
-  content::NavigationHandle* navigation_handle = throttle->navigation_handle();
+  content::WebContents* contents =
+      throttle->navigation_handle()->GetWebContents();
+  DCHECK(!contents->IsVisible());
+
+  // Skip delaying the navigation if this tab is in session restore, whose
+  // loading is already controlled by TabLoader.
+  if (GetWebContentsData(contents)->is_in_session_restore())
+    return content::NavigationThrottle::PROCEED;
+
+  if (background_tab_loading_mode_ == BackgroundTabLoadingMode::kStaggered &&
+      !IsInBackgroundTabOpeningSession()) {
+    stats_collector_->OnBackgroundTabOpeningSessionStarted();
+  }
+
   if (!base::FeatureList::IsEnabled(
-          features::kStaggeredBackgroundTabOpenExperiment) ||
+          features::kStaggeredBackgroundTabOpeningExperiment) ||
       CanLoadNextTab()) {
-    loading_contents_.insert(navigation_handle->GetWebContents());
+    loading_contents_.insert(contents);
     return content::NavigationThrottle::PROCEED;
   }
 
   // TODO(zhenw): Try to set the favicon and title from history service if this
   // navigation will be delayed.
-  GetWebContentsData(navigation_handle->GetWebContents())
-      ->SetTabLoadingState(TAB_IS_NOT_LOADING);
+  GetWebContentsData(contents)->SetTabLoadingState(TAB_IS_NOT_LOADING);
   pending_navigations_.push_back(throttle);
   std::stable_sort(pending_navigations_.begin(), pending_navigations_.end(),
                    ComparePendingNavigations);
@@ -1143,6 +1157,9 @@
 }
 
 bool TabManager::CanLoadNextTab() const {
+  if (background_tab_loading_mode_ != BackgroundTabLoadingMode::kStaggered)
+    return false;
+
   // TabManager can only load the next tab when the loading slots free up. The
   // loading slot limit can be exceeded when |force_load_timer_| fires or when
   // the user selects a background tab.
@@ -1174,16 +1191,32 @@
 
 void TabManager::OnDidStopLoading(content::WebContents* contents) {
   DCHECK_EQ(TAB_IS_LOADED, GetWebContentsData(contents)->tab_loading_state());
+  bool was_in_background_tab_opening_session =
+      IsInBackgroundTabOpeningSession();
+
   loading_contents_.erase(contents);
   stats_collector_->OnDidStopLoading(contents);
   LoadNextBackgroundTabIfNeeded();
+
+  if (was_in_background_tab_opening_session &&
+      !IsInBackgroundTabOpeningSession()) {
+    stats_collector_->OnBackgroundTabOpeningSessionEnded();
+  }
 }
 
 void TabManager::OnWebContentsDestroyed(content::WebContents* contents) {
+  bool was_in_background_tab_opening_session =
+      IsInBackgroundTabOpeningSession();
+
   RemovePendingNavigationIfNeeded(contents);
   loading_contents_.erase(contents);
   stats_collector_->OnWebContentsDestroyed(contents);
   LoadNextBackgroundTabIfNeeded();
+
+  if (was_in_background_tab_opening_session &&
+      !IsInBackgroundTabOpeningSession()) {
+    stats_collector_->OnBackgroundTabOpeningSessionEnded();
+  }
 }
 
 void TabManager::StartForceLoadTimer() {
diff --git a/chrome/browser/resource_coordinator/tab_manager.h b/chrome/browser/resource_coordinator/tab_manager.h
index 2a4448f..7acc7baa 100644
--- a/chrome/browser/resource_coordinator/tab_manager.h
+++ b/chrome/browser/resource_coordinator/tab_manager.h
@@ -226,11 +226,6 @@
   // foreground.
   bool IsTabRestoredInForeground(content::WebContents* web_contents) const;
 
-  // Returns whether the tab manager is currently loading background tabs. This
-  // always returns false during an ongoing session restore, even if background
-  // tabs are being loaded, in order to separate the two activities.
-  bool IsLoadingBackgroundTabs() const;
-
  private:
   friend class TabManagerStatsCollectorTest;
 
@@ -264,9 +259,14 @@
   FRIEND_TEST_ALL_PREFIXES(TabManagerTest, BackgroundTabLoadingMode);
   FRIEND_TEST_ALL_PREFIXES(TabManagerTest, BackgroundTabLoadingSlots);
   FRIEND_TEST_ALL_PREFIXES(TabManagerTest, BackgroundTabsLoadingOrdering);
-  FRIEND_TEST_ALL_PREFIXES(TabManagerTest, IsLoadingBackgroundTabs);
+  FRIEND_TEST_ALL_PREFIXES(TabManagerTest, PauseAndResumeBackgroundTabOpening);
+  FRIEND_TEST_ALL_PREFIXES(TabManagerTest, IsInBackgroundTabOpeningSession);
   FRIEND_TEST_ALL_PREFIXES(TabManagerWithExperimentDisabledTest,
-                           IsLoadingBackgroundTabs);
+                           IsInBackgroundTabOpeningSession);
+  FRIEND_TEST_ALL_PREFIXES(TabManagerTest,
+                           SessionRestoreBeforeBackgroundTabOpeningSession);
+  FRIEND_TEST_ALL_PREFIXES(TabManagerTest,
+                           SessionRestoreAfterBackgroundTabOpeningSession);
   FRIEND_TEST_ALL_PREFIXES(TabManagerTest,
                            ProactiveFastShutdownSingleTabProcess);
   FRIEND_TEST_ALL_PREFIXES(TabManagerTest, UrgentFastShutdownSingleTabProcess);
@@ -371,6 +371,11 @@
                                              TabStripModel* model,
                                              DiscardTabCondition condition);
 
+  // Pause or resume background tab opening according to memory pressure change
+  // if there are pending background tabs.
+  void PauseBackgroundTabOpeningIfNeeded();
+  void ResumeBackgroundTabOpeningIfNeeded();
+
   // Called by the memory pressure listener when the memory pressure rises.
   void OnMemoryPressure(
       base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level);
@@ -424,6 +429,14 @@
   void OnSessionRestoreFinishedLoadingTabs();
   void OnWillRestoreTab(content::WebContents* web_contents);
 
+  // Returns true if it is in BackgroundTabOpening session, which is defined as
+  // the duration from the time when the browser starts to load background tabs
+  // until the time when browser has finished loading those tabs. During the
+  // session, the session can end when background tabs' loading are paused due
+  // to memory pressure. A new session starts when background tabs' loading
+  // resume when memory pressure returns to normal.
+  bool IsInBackgroundTabOpeningSession() const;
+
   // Returns true if TabManager can start loading next tab.
   bool CanLoadNextTab() const;
 
diff --git a/chrome/browser/resource_coordinator/tab_manager_stats_collector.cc b/chrome/browser/resource_coordinator/tab_manager_stats_collector.cc
index 0d4efe2..5f5e584 100644
--- a/chrome/browser/resource_coordinator/tab_manager_stats_collector.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_stats_collector.cc
@@ -10,6 +10,7 @@
 #include <utility>
 
 #include "base/memory/ptr_util.h"
+#include "base/metrics/histogram.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/stl_util.h"
 #include "base/time/time.h"
@@ -19,51 +20,57 @@
 
 namespace resource_coordinator {
 
-class TabManagerStatsCollector::SessionRestoreSwapMetricsDelegate
+namespace {
+
+const char* kSessionTypeName[] = {"SessionRestore", "BackgroundTabOpening"};
+
+}  // namespace
+
+class TabManagerStatsCollector::SwapMetricsDelegate
     : public content::SwapMetricsDriver::Delegate {
  public:
-  explicit SessionRestoreSwapMetricsDelegate(
-      TabManagerStatsCollector* tab_manager_stats_collector)
-      : tab_manager_stats_collector_(tab_manager_stats_collector) {}
+  explicit SwapMetricsDelegate(
+      TabManagerStatsCollector* tab_manager_stats_collector,
+      SessionType type)
+      : tab_manager_stats_collector_(tab_manager_stats_collector),
+        session_type_(type) {}
 
-  ~SessionRestoreSwapMetricsDelegate() override = default;
+  ~SwapMetricsDelegate() override = default;
 
   void OnSwapInCount(uint64_t count, base::TimeDelta interval) override {
-    tab_manager_stats_collector_->OnSessionRestoreSwapInCount(count, interval);
+    tab_manager_stats_collector_->RecordSwapMetrics(
+        session_type_, "SwapInPerSecond", count, interval);
   }
 
   void OnSwapOutCount(uint64_t count, base::TimeDelta interval) override {
-    tab_manager_stats_collector_->OnSessionRestoreSwapOutCount(count, interval);
+    tab_manager_stats_collector_->RecordSwapMetrics(
+        session_type_, "SwapOutPerSecond", count, interval);
   }
 
   void OnDecompressedPageCount(uint64_t count,
                                base::TimeDelta interval) override {
-    tab_manager_stats_collector_->OnSessionRestoreDecompressedPageCount(
-        count, interval);
+    tab_manager_stats_collector_->RecordSwapMetrics(
+        session_type_, "DecompressedPagesPerSecond", count, interval);
   }
 
   void OnCompressedPageCount(uint64_t count,
                              base::TimeDelta interval) override {
-    tab_manager_stats_collector_->OnSessionRestoreCompressedPageCount(count,
-                                                                      interval);
+    tab_manager_stats_collector_->RecordSwapMetrics(
+        session_type_, "CompressedPagesPerSecond", count, interval);
   }
 
-  void OnSessionRestoreUpdateMetricsFailed() {
-    tab_manager_stats_collector_->OnSessionRestoreUpdateMetricsFailed();
+  void OnUpdateMetricsFailed() override {
+    tab_manager_stats_collector_->OnUpdateSwapMetricsFailed();
   }
 
  private:
   TabManagerStatsCollector* tab_manager_stats_collector_;
+  const SessionType session_type_;
 };
 
 TabManagerStatsCollector::TabManagerStatsCollector()
     : is_session_restore_loading_tabs_(false),
       is_in_background_tab_opening_session_(false) {
-  std::unique_ptr<content::SwapMetricsDriver::Delegate> delegate(
-      base::WrapUnique<content::SwapMetricsDriver::Delegate>(
-          new SessionRestoreSwapMetricsDelegate(this)));
-  session_restore_swap_metrics_driver_ = content::SwapMetricsDriver::Create(
-      std::move(delegate), base::TimeDelta::FromSeconds(0));
   SessionRestore::AddObserver(this);
 }
 
@@ -79,6 +86,9 @@
     return;
   }
 
+  if (IsInOverlappedSession())
+    return;
+
   auto* new_data = TabManager::WebContentsData::FromWebContents(new_contents);
   DCHECK(new_data);
 
@@ -92,6 +102,7 @@
                               new_data->tab_loading_state(),
                               TAB_LOADING_STATE_MAX);
   }
+
   if (old_contents)
     foreground_contents_switched_to_times_.erase(old_contents);
   DCHECK(
@@ -105,13 +116,19 @@
 void TabManagerStatsCollector::RecordExpectedTaskQueueingDuration(
     content::WebContents* contents,
     base::TimeDelta queueing_time) {
-  if (is_session_restore_loading_tabs_ && contents->IsVisible()) {
+  if (!contents->IsVisible())
+    return;
+
+  if (IsInOverlappedSession())
+    return;
+
+  if (is_session_restore_loading_tabs_) {
     UMA_HISTOGRAM_TIMES(
         kHistogramSessionRestoreForegroundTabExpectedTaskQueueingDuration,
         queueing_time);
   }
 
-  if (is_in_background_tab_opening_session_ && contents->IsVisible()) {
+  if (is_in_background_tab_opening_session_) {
     UMA_HISTOGRAM_TIMES(
         kHistogramBackgroundTabOpeningForegroundTabExpectedTaskQueueingDuration,
         queueing_time);
@@ -120,69 +137,71 @@
 
 void TabManagerStatsCollector::OnSessionRestoreStartedLoadingTabs() {
   DCHECK(!is_session_restore_loading_tabs_);
-  if (session_restore_swap_metrics_driver_)
-    session_restore_swap_metrics_driver_->InitializeMetrics();
+
+  CreateAndInitSwapMetricsDriverIfNeeded(SessionType::kSessionRestore);
+
   is_session_restore_loading_tabs_ = true;
+  ClearStatsWhenInOverlappedSession();
 }
 
 void TabManagerStatsCollector::OnSessionRestoreFinishedLoadingTabs() {
   DCHECK(is_session_restore_loading_tabs_);
-  if (session_restore_swap_metrics_driver_)
-    session_restore_swap_metrics_driver_->UpdateMetrics();
+  if (swap_metrics_driver_)
+    swap_metrics_driver_->UpdateMetrics();
   is_session_restore_loading_tabs_ = false;
 }
 
 void TabManagerStatsCollector::OnBackgroundTabOpeningSessionStarted() {
   DCHECK(!is_in_background_tab_opening_session_);
+
+  CreateAndInitSwapMetricsDriverIfNeeded(SessionType::kBackgroundTabOpening);
+
   is_in_background_tab_opening_session_ = true;
+  ClearStatsWhenInOverlappedSession();
 }
 
 void TabManagerStatsCollector::OnBackgroundTabOpeningSessionEnded() {
   DCHECK(is_in_background_tab_opening_session_);
+  if (swap_metrics_driver_)
+    swap_metrics_driver_->UpdateMetrics();
   is_in_background_tab_opening_session_ = false;
 }
 
-void TabManagerStatsCollector::OnSessionRestoreSwapInCount(
-    uint64_t count,
-    base::TimeDelta interval) {
-  DCHECK(is_session_restore_loading_tabs_);
-  UMA_HISTOGRAM_COUNTS_10000(
-      "TabManager.SessionRestore.SwapInPerSecond",
-      static_cast<double>(count) / interval.InSecondsF());
+void TabManagerStatsCollector::CreateAndInitSwapMetricsDriverIfNeeded(
+    SessionType type) {
+  if (IsInOverlappedSession()) {
+    swap_metrics_driver_ = nullptr;
+    return;
+  }
+
+  // Always create a new instance in case there is a SessionType change because
+  // this is shared between SessionRestore and BackgroundTabOpening.
+  swap_metrics_driver_ = content::SwapMetricsDriver::Create(
+      base::WrapUnique<content::SwapMetricsDriver::Delegate>(
+          new SwapMetricsDelegate(this, type)),
+      base::TimeDelta::FromSeconds(0));
+  // The driver could still be null on a platform with no swap driver support.
+  if (swap_metrics_driver_)
+    swap_metrics_driver_->InitializeMetrics();
 }
 
-void TabManagerStatsCollector::OnSessionRestoreSwapOutCount(
+void TabManagerStatsCollector::RecordSwapMetrics(
+    SessionType type,
+    const std::string& metric_name,
     uint64_t count,
-    base::TimeDelta interval) {
-  DCHECK(is_session_restore_loading_tabs_);
-  UMA_HISTOGRAM_COUNTS_10000(
-      "TabManager.SessionRestore.SwapOutPerSecond",
-      static_cast<double>(count) / interval.InSecondsF());
+    const base::TimeDelta& interval) {
+  base::HistogramBase* histogram = base::Histogram::FactoryGet(
+      "TabManager.Experimental." + std::string(kSessionTypeName[type]) + "." +
+          metric_name,
+      1,      // minimum
+      10000,  // maximum
+      50,     // bucket_count
+      base::HistogramBase::kUmaTargetedHistogramFlag);
+  histogram->Add(static_cast<double>(count) / interval.InSecondsF());
 }
 
-void TabManagerStatsCollector::OnSessionRestoreDecompressedPageCount(
-    uint64_t count,
-    base::TimeDelta interval) {
-  DCHECK(is_session_restore_loading_tabs_);
-  UMA_HISTOGRAM_COUNTS_10000(
-      "TabManager.SessionRestore.DecompressedPagesPerSecond",
-      static_cast<double>(count) / interval.InSecondsF());
-}
-
-void TabManagerStatsCollector::OnSessionRestoreCompressedPageCount(
-    uint64_t count,
-    base::TimeDelta interval) {
-  DCHECK(is_session_restore_loading_tabs_);
-  UMA_HISTOGRAM_COUNTS_10000(
-      "TabManager.SessionRestore.CompressedPagesPerSecond",
-      static_cast<double>(count) / interval.InSecondsF());
-}
-
-void TabManagerStatsCollector::OnSessionRestoreUpdateMetricsFailed() {
-  // If either InitializeMetrics() or UpdateMetrics() fails, it's unlikely an
-  // error that can be recovered from, in which case we don't collect swap
-  // metrics for session restore.
-  session_restore_swap_metrics_driver_.reset();
+void TabManagerStatsCollector::OnUpdateSwapMetricsFailed() {
+  swap_metrics_driver_ = nullptr;
 }
 
 void TabManagerStatsCollector::OnDidStartMainFrameNavigation(
@@ -194,16 +213,18 @@
     content::WebContents* contents) {
   if (!base::ContainsKey(foreground_contents_switched_to_times_, contents))
     return;
-  if (is_session_restore_loading_tabs_) {
+
+  if (is_session_restore_loading_tabs_ && !IsInOverlappedSession()) {
     UMA_HISTOGRAM_TIMES(kHistogramSessionRestoreTabSwitchLoadTime,
                         base::TimeTicks::Now() -
                             foreground_contents_switched_to_times_[contents]);
   }
-  if (is_in_background_tab_opening_session_) {
+  if (is_in_background_tab_opening_session_ && !IsInOverlappedSession()) {
     UMA_HISTOGRAM_TIMES(kHistogramBackgroundTabOpeningTabSwitchLoadTime,
                         base::TimeTicks::Now() -
                             foreground_contents_switched_to_times_[contents]);
   }
+
   foreground_contents_switched_to_times_.erase(contents);
 }
 
@@ -212,6 +233,19 @@
   foreground_contents_switched_to_times_.erase(contents);
 }
 
+bool TabManagerStatsCollector::IsInOverlappedSession() {
+  return is_session_restore_loading_tabs_ &&
+         is_in_background_tab_opening_session_;
+}
+
+void TabManagerStatsCollector::ClearStatsWhenInOverlappedSession() {
+  if (!IsInOverlappedSession())
+    return;
+
+  swap_metrics_driver_ = nullptr;
+  foreground_contents_switched_to_times_.clear();
+}
+
 // static
 const char TabManagerStatsCollector::
     kHistogramSessionRestoreForegroundTabExpectedTaskQueueingDuration[] =
diff --git a/chrome/browser/resource_coordinator/tab_manager_stats_collector.h b/chrome/browser/resource_coordinator/tab_manager_stats_collector.h
index 92621c3..718ff45 100644
--- a/chrome/browser/resource_coordinator/tab_manager_stats_collector.h
+++ b/chrome/browser/resource_coordinator/tab_manager_stats_collector.h
@@ -7,6 +7,7 @@
 
 #include <cstdint>
 #include <memory>
+#include <string>
 #include <unordered_map>
 
 #include "base/gtest_prod_util.h"
@@ -25,9 +26,37 @@
 namespace resource_coordinator {
 
 // TabManagerStatsCollector records UMAs on behalf of TabManager for tab and
-// system-related events and properties during session restore.
+// system-related events and properties during session restore or background tab
+// opening session.
 class TabManagerStatsCollector : public SessionRestoreObserver {
  public:
+  enum SessionType {
+    // SessionRestore is the duration from the time when the browser starts to
+    // restore tabs until the time when the browser has finished loading those
+    // tabs or when the browser stops loading tabs due to memory pressure.
+    // During SessionRestore, some other tabs could be open due to user action,
+    // but that would not affect the session end time point. For example, a
+    // browser starts to restore tab1 and tab2. Tab3 is open due to user
+    // clicking a link in tab1. SessionRestore ends after tab1 and tab2 finishes
+    // loading, even if tab3 is still loading.
+    kSessionRestore,
+
+    // BackgroundTabOpening session is the duration from the time when the
+    // browser starts to open background tabs until the time when browser has
+    // finished loading those tabs or paused loading due to memory pressure.
+    // A new session starts when the browser resumes loading background tabs
+    // when memory pressure returns to normal. During the BackgroundTabOpening
+    // session, some background tabs could become foreground due to user action,
+    // but that would not affect the session end time point. For example, a
+    // browser has tab1 in foreground, and starts to open tab2 and tab3 in
+    // background. The session will end after tab2 and tab3 finishes loading,
+    // even if tab2 and tab3 are brought to foreground before they are loaded.
+    // BackgroundTabOpening session excludes the background tabs being
+    // controlled by SessionRestore, so that those two activities are clearly
+    // separated.
+    kBackgroundTabOpening
+  };
+
   TabManagerStatsCollector();
   ~TabManagerStatsCollector();
 
@@ -45,20 +74,19 @@
   void OnSessionRestoreStartedLoadingTabs() override;
   void OnSessionRestoreFinishedLoadingTabs() override;
 
-  // The following two functions define the start and end of a background tab
+  // The following two functions defines the start and end of a background tab
   // opening session.
   void OnBackgroundTabOpeningSessionStarted();
   void OnBackgroundTabOpeningSessionEnded();
 
-  // The following record UMA histograms for system swap metrics during session
-  // restore.
-  void OnSessionRestoreSwapInCount(uint64_t count, base::TimeDelta interval);
-  void OnSessionRestoreSwapOutCount(uint64_t count, base::TimeDelta interval);
-  void OnSessionRestoreDecompressedPageCount(uint64_t count,
-                                             base::TimeDelta interval);
-  void OnSessionRestoreCompressedPageCount(uint64_t count,
-                                           base::TimeDelta interval);
-  void OnSessionRestoreUpdateMetricsFailed();
+  // Record UMA histograms for system swap metrics.
+  void RecordSwapMetrics(SessionType type,
+                         const std::string& metric_name,
+                         uint64_t count,
+                         const base::TimeDelta& interval);
+
+  // Handles the situation when failing to update swap metrics.
+  void OnUpdateSwapMetricsFailed();
 
   // Called by WebContentsData when a tab starts loading. Used to clean up
   // |foreground_contents_switched_to_times_| if we were tracking this tab and
@@ -75,8 +103,12 @@
   // OnDidStopLoading has not yet been called for it.
   void OnWebContentsDestroyed(content::WebContents* contents);
 
+  bool is_in_background_tab_opening_session() const {
+    return is_in_background_tab_opening_session_;
+  }
+
  private:
-  class SessionRestoreSwapMetricsDelegate;
+  class SwapMetricsDelegate;
   FRIEND_TEST_ALL_PREFIXES(TabManagerStatsCollectorTest,
                            HistogramsExpectedTaskQueueingDuration);
   FRIEND_TEST_ALL_PREFIXES(TabManagerStatsCollectorTabSwitchTest,
@@ -84,6 +116,21 @@
   FRIEND_TEST_ALL_PREFIXES(TabManagerStatsCollectorTabSwitchTest,
                            HistogramsTabSwitchLoadTime);
 
+  // Returns true if the browser is currently in more than one session with
+  // different types. We do not want to report metrics in this situation to have
+  // meaningful results. For example, SessionRestore and BackgroundTabOpening
+  // session could overlap.
+  bool IsInOverlappedSession();
+
+  // This is called when we enter overlapped session. We need to clear all stats
+  // in such situation to avoid reporting mixed metric results.
+  void ClearStatsWhenInOverlappedSession();
+
+  // Create and initialize the swap metrics driver if needed. This will set the
+  // driver to null when it is in overlapped session situation, so that we do
+  // not report swap metrics.
+  void CreateAndInitSwapMetricsDriverIfNeeded(SessionType type);
+
   static const char
       kHistogramSessionRestoreForegroundTabExpectedTaskQueueingDuration[];
   static const char
@@ -96,8 +143,10 @@
   bool is_session_restore_loading_tabs_;
   bool is_in_background_tab_opening_session_;
 
-  std::unique_ptr<content::SwapMetricsDriver>
-      session_restore_swap_metrics_driver_;
+  // This is shared between SessionRestore and BackgroundTabOpening because we
+  // do not report metrics when those two overlap.
+  std::unique_ptr<content::SwapMetricsDriver> swap_metrics_driver_;
+
   // The set of foreground tabs during session restore or background tab opening
   // sessions that were switched to have not yet finished loading, mapped to the
   // time that they were switched to. It's possible to have multiple background
diff --git a/chrome/browser/resource_coordinator/tab_manager_stats_collector_unittest.cc b/chrome/browser/resource_coordinator/tab_manager_stats_collector_unittest.cc
index 93d7aca..1d3b753a 100644
--- a/chrome/browser/resource_coordinator/tab_manager_stats_collector_unittest.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_stats_collector_unittest.cc
@@ -61,6 +61,10 @@
   }
 
  protected:
+  bool IsTestingOverlappedSession() {
+    return should_test_session_restore_ && should_test_background_tab_opening_;
+  }
+
   base::HistogramTester histogram_tester_;
   bool should_test_session_restore_;
   bool should_test_background_tab_opening_;
@@ -146,7 +150,7 @@
   SwitchToBackgroundTab();
   SwitchToBackgroundTab();
   for (const auto& param : histogram_parameters) {
-    if (param.enabled) {
+    if (param.enabled && !IsTestingOverlappedSession()) {
       histogram_tester_.ExpectTotalCount(param.histogram_name, 2);
       histogram_tester_.ExpectBucketCount(param.histogram_name,
                                           TAB_IS_NOT_LOADING, 2);
@@ -161,7 +165,7 @@
   SwitchToBackgroundTab();
   SwitchToBackgroundTab();
   for (const auto& param : histogram_parameters) {
-    if (param.enabled) {
+    if (param.enabled && !IsTestingOverlappedSession()) {
       histogram_tester_.ExpectTotalCount(param.histogram_name, 5);
       histogram_tester_.ExpectBucketCount(param.histogram_name,
                                           TAB_IS_NOT_LOADING, 2);
@@ -179,7 +183,7 @@
   SwitchToBackgroundTab();
   SwitchToBackgroundTab();
   for (const auto& param : histogram_parameters) {
-    if (param.enabled) {
+    if (param.enabled && !IsTestingOverlappedSession()) {
       histogram_tester_.ExpectTotalCount(param.histogram_name, 9);
       histogram_tester_.ExpectBucketCount(param.histogram_name,
                                           TAB_IS_NOT_LOADING, 2);
@@ -209,20 +213,22 @@
   FinishLoadingForegroundTab();
   histogram_tester_.ExpectTotalCount(
       TabManagerStatsCollector::kHistogramSessionRestoreTabSwitchLoadTime,
-      should_test_session_restore_ ? 1 : 0);
+      should_test_session_restore_ && !IsTestingOverlappedSession() ? 1 : 0);
   histogram_tester_.ExpectTotalCount(
       TabManagerStatsCollector::kHistogramBackgroundTabOpeningTabSwitchLoadTime,
-      should_test_background_tab_opening_ ? 1 : 0);
+      should_test_background_tab_opening_ && !IsTestingOverlappedSession() ? 1
+                                                                           : 0);
 
   SetBackgroundTabLoadingState(TAB_IS_LOADING);
   SwitchToBackgroundTab();
   FinishLoadingForegroundTab();
   histogram_tester_.ExpectTotalCount(
       TabManagerStatsCollector::kHistogramSessionRestoreTabSwitchLoadTime,
-      should_test_session_restore_ ? 2 : 0);
+      should_test_session_restore_ && !IsTestingOverlappedSession() ? 2 : 0);
   histogram_tester_.ExpectTotalCount(
       TabManagerStatsCollector::kHistogramBackgroundTabOpeningTabSwitchLoadTime,
-      should_test_background_tab_opening_ ? 2 : 0);
+      should_test_background_tab_opening_ && !IsTestingOverlappedSession() ? 2
+                                                                           : 0);
 
   // Metrics aren't recorded when the foreground tab has not finished loading
   // and the user switches to a different tab.
@@ -236,10 +242,11 @@
   SwitchToBackgroundTab();
   histogram_tester_.ExpectTotalCount(
       TabManagerStatsCollector::kHistogramSessionRestoreTabSwitchLoadTime,
-      should_test_session_restore_ ? 2 : 0);
+      should_test_session_restore_ && !IsTestingOverlappedSession() ? 2 : 0);
   histogram_tester_.ExpectTotalCount(
       TabManagerStatsCollector::kHistogramBackgroundTabOpeningTabSwitchLoadTime,
-      should_test_background_tab_opening_ ? 2 : 0);
+      should_test_background_tab_opening_ && !IsTestingOverlappedSession() ? 2
+                                                                           : 0);
 
   // The count shouldn't change when we're no longer in a session restore or
   // background tab opening.
@@ -247,16 +254,18 @@
     FinishSessionRestore();
   if (should_test_background_tab_opening_)
     FinishBackgroundTabOpeningSession();
+
   SetBackgroundTabLoadingState(TAB_IS_NOT_LOADING);
   SetForegroundTabLoadingState(TAB_IS_LOADED);
   SwitchToBackgroundTab();
   FinishLoadingForegroundTab();
   histogram_tester_.ExpectTotalCount(
       TabManagerStatsCollector::kHistogramSessionRestoreTabSwitchLoadTime,
-      should_test_session_restore_ ? 2 : 0);
+      should_test_session_restore_ && !IsTestingOverlappedSession() ? 2 : 0);
   histogram_tester_.ExpectTotalCount(
       TabManagerStatsCollector::kHistogramBackgroundTabOpeningTabSwitchLoadTime,
-      should_test_background_tab_opening_ ? 2 : 0);
+      should_test_background_tab_opening_ && !IsTestingOverlappedSession() ? 2
+                                                                           : 0);
 }
 
 TEST_P(TabManagerStatsCollectorTest, HistogramsExpectedTaskQueueingDuration) {
@@ -299,11 +308,12 @@
   histogram_tester_.ExpectTotalCount(
       TabManagerStatsCollector::
           kHistogramSessionRestoreForegroundTabExpectedTaskQueueingDuration,
-      should_test_session_restore_ ? 1 : 0);
+      should_test_session_restore_ && !IsTestingOverlappedSession() ? 1 : 0);
   histogram_tester_.ExpectTotalCount(
       TabManagerStatsCollector::
           kHistogramBackgroundTabOpeningForegroundTabExpectedTaskQueueingDuration,
-      should_test_background_tab_opening_ ? 1 : 0);
+      should_test_background_tab_opening_ && !IsTestingOverlappedSession() ? 1
+                                                                           : 0);
 
   if (should_test_session_restore_)
     FinishSessionRestore();
@@ -316,11 +326,12 @@
   histogram_tester_.ExpectTotalCount(
       TabManagerStatsCollector::
           kHistogramSessionRestoreForegroundTabExpectedTaskQueueingDuration,
-      should_test_session_restore_ ? 1 : 0);
+      should_test_session_restore_ && !IsTestingOverlappedSession() ? 1 : 0);
   histogram_tester_.ExpectTotalCount(
       TabManagerStatsCollector::
           kHistogramBackgroundTabOpeningForegroundTabExpectedTaskQueueingDuration,
-      should_test_background_tab_opening_ ? 1 : 0);
+      should_test_background_tab_opening_ && !IsTestingOverlappedSession() ? 1
+                                                                           : 0);
 }
 
 INSTANTIATE_TEST_CASE_P(
diff --git a/chrome/browser/resource_coordinator/tab_manager_unittest.cc b/chrome/browser/resource_coordinator/tab_manager_unittest.cc
index cce45cc2..bff131e 100644
--- a/chrome/browser/resource_coordinator/tab_manager_unittest.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_unittest.cc
@@ -22,6 +22,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/resource_coordinator/background_tab_navigation_throttle.h"
+#include "chrome/browser/resource_coordinator/tab_manager_stats_collector.h"
 #include "chrome/browser/resource_coordinator/tab_manager_web_contents_data.h"
 #include "chrome/browser/resource_coordinator/tab_stats.h"
 #include "chrome/browser/sessions/tab_loader.h"
@@ -133,19 +134,9 @@
     return web_contents;
   }
 
-  std::unique_ptr<NavigationHandle> CreateTabAndNavigation(const char* url) {
-    content::TestWebContents* web_contents =
-        content::TestWebContents::Create(profile(), nullptr);
-    return content::NavigationHandle::CreateNavigationHandleForTesting(
-        GURL(url), web_contents->GetMainFrame());
-  }
-
-  // Simulate creating 3 tabs and their navigations.
-  void MaybeThrottleNavigations(TabManager* tab_manager,
-                                size_t loading_slots = 1,
-                                const char* url1 = kTestUrl,
-                                const char* url2 = kTestUrl,
-                                const char* url3 = kTestUrl) {
+  void PrepareTabs(const char* url1 = kTestUrl,
+                   const char* url2 = kTestUrl,
+                   const char* url3 = kTestUrl) {
     nav_handle1_ = CreateTabAndNavigation(url1);
     nav_handle2_ = CreateTabAndNavigation(url2);
     nav_handle3_ = CreateTabAndNavigation(url3);
@@ -153,7 +144,7 @@
     contents2_ = nav_handle2_->GetWebContents();
     contents3_ = nav_handle3_->GetWebContents();
 
-    contents1_->WasShown();
+    contents1_->WasHidden();
     contents2_->WasHidden();
     contents3_->WasHidden();
 
@@ -163,6 +154,15 @@
         nav_handle2_.get());
     throttle3_ = base::MakeUnique<NonResumingBackgroundTabNavigationThrottle>(
         nav_handle3_.get());
+  }
+
+  // Simulate creating 3 tabs and their navigations.
+  void MaybeThrottleNavigations(TabManager* tab_manager,
+                                size_t loading_slots = 1,
+                                const char* url1 = kTestUrl,
+                                const char* url2 = kTestUrl,
+                                const char* url3 = kTestUrl) {
+    PrepareTabs(url1, url2, url3);
 
     NavigationThrottle::ThrottleCheckResult result1 =
         tab_manager->MaybeThrottleNavigation(throttle1_.get());
@@ -200,6 +200,13 @@
   }
 
  protected:
+  std::unique_ptr<NavigationHandle> CreateTabAndNavigation(const char* url) {
+    content::TestWebContents* web_contents =
+        content::TestWebContents::Create(profile(), nullptr);
+    return content::NavigationHandle::CreateNavigationHandleForTesting(
+        GURL(url), web_contents->GetMainFrame());
+  }
+
   std::unique_ptr<BackgroundTabNavigationThrottle> throttle1_;
   std::unique_ptr<BackgroundTabNavigationThrottle> throttle2_;
   std::unique_ptr<BackgroundTabNavigationThrottle> throttle3_;
@@ -215,7 +222,7 @@
  public:
   void SetUp() override {
     scoped_feature_list_.InitAndDisableFeature(
-        features::kStaggeredBackgroundTabOpenExperiment);
+        features::kStaggeredBackgroundTabOpeningExperiment);
     ChromeRenderViewHostTestHarness::SetUp();
   }
 
@@ -1010,39 +1017,112 @@
   EXPECT_FALSE(tab_manager->IsNavigationDelayedForTest(nav_handle3_.get()));
 }
 
-TEST_F(TabManagerTest, IsLoadingBackgroundTabs) {
+TEST_F(TabManagerTest, PauseAndResumeBackgroundTabOpening) {
   TabManager* tab_manager = g_browser_process->GetTabManager();
   tab_manager->ResetMemoryPressureListenerForTest();
-  EXPECT_FALSE(tab_manager->IsLoadingBackgroundTabs());
+  PrepareTabs();
+
+  EXPECT_EQ(TabManager::BackgroundTabLoadingMode::kStaggered,
+            tab_manager->background_tab_loading_mode_);
+  EXPECT_FALSE(tab_manager->IsInBackgroundTabOpeningSession());
+  EXPECT_FALSE(
+      tab_manager->stats_collector()->is_in_background_tab_opening_session());
+
+  // Start background tab opening session.
+  EXPECT_EQ(content::NavigationThrottle::PROCEED,
+            tab_manager->MaybeThrottleNavigation(throttle1_.get()));
+  tab_manager->GetWebContentsData(contents1_)
+      ->DidStartNavigation(nav_handle1_.get());
+  EXPECT_TRUE(tab_manager->IsInBackgroundTabOpeningSession());
+  EXPECT_TRUE(
+      tab_manager->stats_collector()->is_in_background_tab_opening_session());
+
+  // Simulate memory pressure getting high. TabManager pause loading pending
+  // background tabs, and ends the background tab opening session.
+  tab_manager->OnMemoryPressure(
+      base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE);
+  EXPECT_EQ(TabManager::BackgroundTabLoadingMode::kPaused,
+            tab_manager->background_tab_loading_mode_);
+  EXPECT_FALSE(tab_manager->IsInBackgroundTabOpeningSession());
+  EXPECT_FALSE(
+      tab_manager->stats_collector()->is_in_background_tab_opening_session());
+
+  // Simulate tab 1 has finished loading, which was scheduled to load before
+  // pausing.
+  tab_manager->GetWebContentsData(contents1_)->DidStopLoading();
+
+  // TabManager cannot enter BackgroundTabOpening session when it is in paused
+  // mode.
+  EXPECT_EQ(content::NavigationThrottle::DEFER,
+            tab_manager->MaybeThrottleNavigation(throttle2_.get()));
+  EXPECT_TRUE(tab_manager->IsNavigationDelayedForTest(nav_handle2_.get()));
+  EXPECT_FALSE(tab_manager->IsInBackgroundTabOpeningSession());
+  EXPECT_FALSE(
+      tab_manager->stats_collector()->is_in_background_tab_opening_session());
+
+  // Simulate memory pressure is relieved. TabManager will reset the loading
+  // mode and try to load the next tab. If there is pending tab, TabManager
+  // starts a new BackgroundTabOpening session.
+  tab_manager->OnMemoryPressure(
+      base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE);
+  EXPECT_EQ(TabManager::BackgroundTabLoadingMode::kStaggered,
+            tab_manager->background_tab_loading_mode_);
+  EXPECT_TRUE(tab_manager->IsInBackgroundTabOpeningSession());
+  EXPECT_TRUE(
+      tab_manager->stats_collector()->is_in_background_tab_opening_session());
+
+  // Tab 2 should start loading right away.
+  EXPECT_TRUE(tab_manager->IsTabLoadingForTest(contents2_));
+  EXPECT_FALSE(tab_manager->IsNavigationDelayedForTest(nav_handle2_.get()));
+}
+
+TEST_F(TabManagerTest, IsInBackgroundTabOpeningSession) {
+  TabManager* tab_manager = g_browser_process->GetTabManager();
+  tab_manager->ResetMemoryPressureListenerForTest();
+  EXPECT_FALSE(tab_manager->IsInBackgroundTabOpeningSession());
+  EXPECT_FALSE(
+      tab_manager->stats_collector()->is_in_background_tab_opening_session());
 
   MaybeThrottleNavigations(tab_manager);
   tab_manager->GetWebContentsData(contents1_)
       ->DidStartNavigation(nav_handle1_.get());
-  EXPECT_TRUE(tab_manager->IsLoadingBackgroundTabs());
+  EXPECT_TRUE(tab_manager->IsInBackgroundTabOpeningSession());
+  EXPECT_TRUE(
+      tab_manager->stats_collector()->is_in_background_tab_opening_session());
 
   tab_manager->GetWebContentsData(contents1_)->DidStopLoading();
-  EXPECT_TRUE(tab_manager->IsLoadingBackgroundTabs());
+  EXPECT_TRUE(tab_manager->IsInBackgroundTabOpeningSession());
+  EXPECT_TRUE(
+      tab_manager->stats_collector()->is_in_background_tab_opening_session());
 
   tab_manager->GetWebContentsData(contents2_)->DidStopLoading();
-  EXPECT_TRUE(tab_manager->IsLoadingBackgroundTabs());
+  EXPECT_TRUE(tab_manager->IsInBackgroundTabOpeningSession());
+  EXPECT_TRUE(
+      tab_manager->stats_collector()->is_in_background_tab_opening_session());
 
+  // It is still in background tab opening session even if tab3 is brought to
+  // foreground. The session only ends after tab1, tab2 and tab3 have all
+  // finished loading.
   contents3_->WasShown();
-  EXPECT_FALSE(tab_manager->IsLoadingBackgroundTabs());
-
-  contents3_->WasHidden();
-  EXPECT_TRUE(tab_manager->IsLoadingBackgroundTabs());
+  EXPECT_TRUE(tab_manager->IsInBackgroundTabOpeningSession());
+  EXPECT_TRUE(
+      tab_manager->stats_collector()->is_in_background_tab_opening_session());
 
   tab_manager->GetWebContentsData(contents3_)->DidStopLoading();
-  EXPECT_FALSE(tab_manager->IsLoadingBackgroundTabs());
+  EXPECT_FALSE(tab_manager->IsInBackgroundTabOpeningSession());
+  EXPECT_FALSE(
+      tab_manager->stats_collector()->is_in_background_tab_opening_session());
 }
 
-TEST_F(TabManagerWithExperimentDisabledTest, IsLoadingBackgroundTabs) {
+TEST_F(TabManagerWithExperimentDisabledTest, IsInBackgroundTabOpeningSession) {
   EXPECT_FALSE(base::FeatureList::IsEnabled(
-      features::kStaggeredBackgroundTabOpenExperiment));
+      features::kStaggeredBackgroundTabOpeningExperiment));
 
   TabManager* tab_manager = g_browser_process->GetTabManager();
   tab_manager->ResetMemoryPressureListenerForTest();
-  EXPECT_FALSE(tab_manager->IsLoadingBackgroundTabs());
+  EXPECT_FALSE(tab_manager->IsInBackgroundTabOpeningSession());
+  EXPECT_FALSE(
+      tab_manager->stats_collector()->is_in_background_tab_opening_session());
 
   MaybeThrottleNavigations(tab_manager);
   tab_manager->GetWebContentsData(contents1_)
@@ -1058,31 +1138,133 @@
   EXPECT_FALSE(tab_manager->IsNavigationDelayedForTest(nav_handle1_.get()));
   EXPECT_FALSE(tab_manager->IsNavigationDelayedForTest(nav_handle2_.get()));
   EXPECT_FALSE(tab_manager->IsNavigationDelayedForTest(nav_handle3_.get()));
-  EXPECT_TRUE(tab_manager->IsLoadingBackgroundTabs());
+  EXPECT_TRUE(tab_manager->IsInBackgroundTabOpeningSession());
+  EXPECT_TRUE(
+      tab_manager->stats_collector()->is_in_background_tab_opening_session());
 
   tab_manager->GetWebContentsData(contents1_)->DidStopLoading();
   EXPECT_FALSE(tab_manager->IsTabLoadingForTest(contents1_));
   EXPECT_TRUE(tab_manager->IsTabLoadingForTest(contents2_));
   EXPECT_TRUE(tab_manager->IsTabLoadingForTest(contents3_));
-  EXPECT_TRUE(tab_manager->IsLoadingBackgroundTabs());
+  EXPECT_TRUE(tab_manager->IsInBackgroundTabOpeningSession());
+  EXPECT_TRUE(
+      tab_manager->stats_collector()->is_in_background_tab_opening_session());
 
   tab_manager->GetWebContentsData(contents2_)->DidStopLoading();
   EXPECT_FALSE(tab_manager->IsTabLoadingForTest(contents1_));
   EXPECT_FALSE(tab_manager->IsTabLoadingForTest(contents2_));
   EXPECT_TRUE(tab_manager->IsTabLoadingForTest(contents3_));
-  EXPECT_TRUE(tab_manager->IsLoadingBackgroundTabs());
+  EXPECT_TRUE(tab_manager->IsInBackgroundTabOpeningSession());
+  EXPECT_TRUE(
+      tab_manager->stats_collector()->is_in_background_tab_opening_session());
 
+  // It is still in background tab opening session even if tab3 is brought to
+  // foreground. The session only ends after tab1, tab2 and tab3 have all
+  // finished loading.
   contents3_->WasShown();
-  EXPECT_FALSE(tab_manager->IsLoadingBackgroundTabs());
-
-  contents3_->WasHidden();
-  EXPECT_TRUE(tab_manager->IsLoadingBackgroundTabs());
+  EXPECT_TRUE(tab_manager->IsInBackgroundTabOpeningSession());
+  EXPECT_TRUE(
+      tab_manager->stats_collector()->is_in_background_tab_opening_session());
 
   tab_manager->GetWebContentsData(contents3_)->DidStopLoading();
   EXPECT_FALSE(tab_manager->IsTabLoadingForTest(contents1_));
   EXPECT_FALSE(tab_manager->IsTabLoadingForTest(contents2_));
   EXPECT_FALSE(tab_manager->IsTabLoadingForTest(contents3_));
-  EXPECT_FALSE(tab_manager->IsLoadingBackgroundTabs());
+  EXPECT_FALSE(tab_manager->IsInBackgroundTabOpeningSession());
+  EXPECT_FALSE(
+      tab_manager->stats_collector()->is_in_background_tab_opening_session());
+}
+
+TEST_F(TabManagerTest, SessionRestoreBeforeBackgroundTabOpeningSession) {
+  TabManager* tab_manager = g_browser_process->GetTabManager();
+  tab_manager->ResetMemoryPressureListenerForTest();
+  PrepareTabs();
+
+  // Start session restore.
+  tab_manager->OnSessionRestoreStartedLoadingTabs();
+  EXPECT_TRUE(tab_manager->IsSessionRestoreLoadingTabs());
+  EXPECT_FALSE(tab_manager->IsInBackgroundTabOpeningSession());
+  EXPECT_FALSE(
+      tab_manager->stats_collector()->is_in_background_tab_opening_session());
+
+  tab_manager->GetWebContentsData(contents1_)->SetIsInSessionRestore(true);
+  tab_manager->GetWebContentsData(contents2_)->SetIsInSessionRestore(false);
+  tab_manager->GetWebContentsData(contents3_)->SetIsInSessionRestore(false);
+
+  // Do not enter BackgroundTabOpening session if the background tab is in
+  // session restore.
+  EXPECT_EQ(content::NavigationThrottle::PROCEED,
+            tab_manager->MaybeThrottleNavigation(throttle1_.get()));
+  EXPECT_FALSE(tab_manager->IsInBackgroundTabOpeningSession());
+  EXPECT_FALSE(
+      tab_manager->stats_collector()->is_in_background_tab_opening_session());
+
+  // Enter BackgroundTabOpening session when there are background tabs not in
+  // session restore, though the first background tab can still proceed.
+  EXPECT_EQ(content::NavigationThrottle::PROCEED,
+            tab_manager->MaybeThrottleNavigation(throttle2_.get()));
+  EXPECT_TRUE(tab_manager->IsInBackgroundTabOpeningSession());
+  EXPECT_TRUE(
+      tab_manager->stats_collector()->is_in_background_tab_opening_session());
+
+  EXPECT_EQ(content::NavigationThrottle::DEFER,
+            tab_manager->MaybeThrottleNavigation(throttle3_.get()));
+  EXPECT_TRUE(tab_manager->IsInBackgroundTabOpeningSession());
+  EXPECT_TRUE(
+      tab_manager->stats_collector()->is_in_background_tab_opening_session());
+
+  // Stop session restore.
+  tab_manager->OnSessionRestoreFinishedLoadingTabs();
+  EXPECT_FALSE(tab_manager->IsSessionRestoreLoadingTabs());
+  EXPECT_TRUE(tab_manager->IsInBackgroundTabOpeningSession());
+  EXPECT_TRUE(
+      tab_manager->stats_collector()->is_in_background_tab_opening_session());
+}
+
+TEST_F(TabManagerTest, SessionRestoreAfterBackgroundTabOpeningSession) {
+  TabManager* tab_manager = g_browser_process->GetTabManager();
+  tab_manager->ResetMemoryPressureListenerForTest();
+  PrepareTabs();
+
+  EXPECT_FALSE(tab_manager->IsSessionRestoreLoadingTabs());
+  EXPECT_FALSE(tab_manager->IsInBackgroundTabOpeningSession());
+  EXPECT_FALSE(
+      tab_manager->stats_collector()->is_in_background_tab_opening_session());
+
+  // Start background tab opening session.
+  EXPECT_EQ(content::NavigationThrottle::PROCEED,
+            tab_manager->MaybeThrottleNavigation(throttle1_.get()));
+  EXPECT_TRUE(tab_manager->IsInBackgroundTabOpeningSession());
+  EXPECT_TRUE(
+      tab_manager->stats_collector()->is_in_background_tab_opening_session());
+
+  EXPECT_EQ(content::NavigationThrottle::DEFER,
+            tab_manager->MaybeThrottleNavigation(throttle2_.get()));
+  EXPECT_TRUE(tab_manager->IsInBackgroundTabOpeningSession());
+  EXPECT_TRUE(
+      tab_manager->stats_collector()->is_in_background_tab_opening_session());
+
+  // Now session restore starts after background tab opening session starts.
+  tab_manager->OnSessionRestoreStartedLoadingTabs();
+  EXPECT_TRUE(tab_manager->IsSessionRestoreLoadingTabs());
+  EXPECT_TRUE(tab_manager->IsInBackgroundTabOpeningSession());
+  EXPECT_TRUE(
+      tab_manager->stats_collector()->is_in_background_tab_opening_session());
+
+  // The following background tabs are still delayed if they are not in session
+  // restore.
+  tab_manager->GetWebContentsData(contents3_)->SetIsInSessionRestore(false);
+  EXPECT_EQ(content::NavigationThrottle::DEFER,
+            tab_manager->MaybeThrottleNavigation(throttle3_.get()));
+
+  // The background tab opening session ends after existing tracked tabs have
+  // finished loading.
+  tab_manager->GetWebContentsData(contents1_)->DidStopLoading();
+  tab_manager->GetWebContentsData(contents2_)->DidStopLoading();
+  tab_manager->GetWebContentsData(contents3_)->DidStopLoading();
+  EXPECT_FALSE(tab_manager->IsInBackgroundTabOpeningSession());
+  EXPECT_FALSE(
+      tab_manager->stats_collector()->is_in_background_tab_opening_session());
 }
 
 TEST_F(TabManagerTest, IsTabRestoredInForeground) {
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/panel.html b/chrome/browser/resources/chromeos/chromevox/cvox2/background/panel.html
index 88a430b..4d4fbc9 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/panel.html
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/panel.html
@@ -43,7 +43,7 @@
       </div>
     </div>
     <div id="search-container">
-      <input class="i18n" msgid="search_widget_intro" id="search" type="search"></input>
+      <input class="i18n" msgid="search_widget_intro" id="search" type="search">
     </div>
   </div>
   <div id="options_close">
diff --git a/chrome/browser/resources/chromeos/login/oobe_voice_interaction_value_prop.js b/chrome/browser/resources/chromeos/login/oobe_voice_interaction_value_prop.js
index e19832f9..d710528 100644
--- a/chrome/browser/resources/chromeos/login/oobe_voice_interaction_value_prop.js
+++ b/chrome/browser/resources/chromeos/login/oobe_voice_interaction_value_prop.js
@@ -201,6 +201,9 @@
         this.onValueViewErrorOccurred();
       }
     }
+    if (details.statusCode != '200') {
+      this.onValueViewErrorOccurred();
+    }
   },
 
   /**
diff --git a/chrome/browser/resources/md_bookmarks/app.html b/chrome/browser/resources/md_bookmarks/app.html
index 88676c04..64992ad 100644
--- a/chrome/browser/resources/md_bookmarks/app.html
+++ b/chrome/browser/resources/md_bookmarks/app.html
@@ -68,9 +68,10 @@
         min-width: 550px;
       }
     </style>
-    <bookmarks-toolbar sidebar-width="[[sidebarWidth_]]"></bookmarks-toolbar>
+    <bookmarks-toolbar sidebar-width="[[sidebarWidth_]]" role="banner">
+    </bookmarks-toolbar>
     <div id="main-container">
-       <div id="sidebar" role="tree">
+       <div id="sidebar" role="navigation">
         <bookmarks-folder-node item-id="0" depth="-1"></bookmarks-folder-node>
       </div>
       <div id="splitter"></div>
diff --git a/chrome/browser/resources/md_bookmarks/command_manager.html b/chrome/browser/resources/md_bookmarks/command_manager.html
index b96e820..508b050 100644
--- a/chrome/browser/resources/md_bookmarks/command_manager.html
+++ b/chrome/browser/resources/md_bookmarks/command_manager.html
@@ -42,7 +42,9 @@
               [[getCommandSublabel_(command, menuIds_)]]
             </span>
           </button>
-          <hr hidden$="[[!showDividerAfter_(command, menuIds_)]]"></hr>
+          <hr hidden$="[[!showDividerAfter_(command, menuIds_)]]"
+              aria-hidden="true">
+          </hr>
         </template>
       </dialog>
     </template>
diff --git a/chrome/browser/resources/md_bookmarks/folder_node.html b/chrome/browser/resources/md_bookmarks/folder_node.html
index 5f1999a1..57a4100 100644
--- a/chrome/browser/resources/md_bookmarks/folder_node.html
+++ b/chrome/browser/resources/md_bookmarks/folder_node.html
@@ -87,8 +87,12 @@
         hidden="[[isRootFolder_(depth)]]"
         role="treeitem">
       <template is="dom-if" if="[[hasChildFolder_]]">
-        <button is="paper-icon-button-light" id="arrow"
-            on-tap="toggleFolder_" on-mousedown="preventDefault_" tabindex="-1">
+        <button is="paper-icon-button-light"
+            id="arrow"
+            on-tap="toggleFolder_"
+            on-mousedown="preventDefault_"
+            tabindex="-1"
+            aria-hidden="true">
           <iron-icon icon="cr:arrow-drop-down" is-open$="[[isOpen]]">
           </iron-icon>
         </button>
diff --git a/chrome/browser/resources/md_bookmarks/item.html b/chrome/browser/resources/md_bookmarks/item.html
index 0754b734..30c219c6 100644
--- a/chrome/browser/resources/md_bookmarks/item.html
+++ b/chrome/browser/resources/md_bookmarks/item.html
@@ -52,7 +52,8 @@
         tabindex$="[[ironListTabIndex]]"
         title="$i18n{moreActionsButtonTitle}"
         on-click="onMenuButtonClick_"
-        on-dblclick="onMenuButtonDblClick_">
+        on-dblclick="onMenuButtonDblClick_"
+        aria-haspopup="menu">
       <div></div>
       <div></div>
       <div></div>
diff --git a/chrome/browser/resources/md_bookmarks/item.js b/chrome/browser/resources/md_bookmarks/item.js
index 07fc634..91e3f03 100644
--- a/chrome/browser/resources/md_bookmarks/item.js
+++ b/chrome/browser/resources/md_bookmarks/item.js
@@ -124,7 +124,10 @@
   /** @private */
   onItemChanged_: function() {
     this.isFolder_ = !this.item_.url;
-    this.setAttribute('aria-label', this.item_.title);
+    this.setAttribute(
+        'aria-label',
+        this.item_.title || this.item_.url ||
+            loadTimeData.getString('folderLabel'));
   },
 
   /**
diff --git a/chrome/browser/resources/md_bookmarks/toolbar.html b/chrome/browser/resources/md_bookmarks/toolbar.html
index 235f09b..55fff095 100644
--- a/chrome/browser/resources/md_bookmarks/toolbar.html
+++ b/chrome/browser/resources/md_bookmarks/toolbar.html
@@ -56,7 +56,8 @@
           id="menuButton"
           class="more-actions more-vert-button"
           title="$i18n{organizeButtonTitle}"
-          on-tap="onMenuButtonOpenTap_">
+          on-tap="onMenuButtonOpenTap_"
+          aria-haspopup="menu">
         <div></div>
         <div></div>
         <div></div>
@@ -70,7 +71,7 @@
             disabled="[[!canSortFolder_]]">
           $i18n{menuSort}
         </button>
-        <hr>
+        <hr aria-hidden="true">
         <button id="addBookmarkButton"
             class="dropdown-item"
             on-tap="onAddBookmarkTap_"
@@ -82,7 +83,7 @@
             disabled="[[!canChangeList_]]">
           $i18n{menuAddFolder}
         </button>
-        <hr>
+        <hr aria-hidden="true">
         <button id="importBookmarkButton"
             class="dropdown-item"
             on-tap="onImportTap_"
diff --git a/chrome/browser/resources/md_extensions/detail_view.html b/chrome/browser/resources/md_extensions/detail_view.html
index f52d9b6..29371c44 100644
--- a/chrome/browser/resources/md_extensions/detail_view.html
+++ b/chrome/browser/resources/md_extensions/detail_view.html
@@ -1,6 +1,7 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 
 <link rel="import" href="chrome://resources/cr_elements/cr_icons_css.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_link_row/cr_link_row.html">
 <link rel="import" href="chrome://resources/cr_elements/hidden_style_css.html">
 <link rel="import" href="chrome://resources/cr_elements/paper_toggle_style_css.html">
 <link rel="import" href="chrome://resources/cr_elements/policy/cr_tooltip_icon.html">
@@ -238,14 +239,10 @@
           <button class="icon-external" is="paper-icon-button-light"></button>
         </div>
       </div>
-      <div class="section actionable"
-          hidden="[[isControlled_(data.controlledInfo)]]" id="remove-extension"
-          on-tap="onRemoveTap_">
-        <div class="control-line">
-          <span>$i18n{itemRemoveExtension}</span>
-          <button class="subpage-arrow" is="paper-icon-button-light"></button>
-        </div>
-      </div>
+      <button is="cr-link-row" hidden="[[isControlled_(data.controlledInfo)]]"
+          icon-class="subpage-arrow" id="remove-extension"
+          label="$i18n{itemRemoveExtension}" on-tap="onRemoveTap_">
+      </button>
       <div class="section block">
         <div class="section-title">$i18n{itemSource}</div>
         <div class="section-content">
diff --git a/chrome/browser/resources/md_extensions/manager.html b/chrome/browser/resources/md_extensions/manager.html
index 8b5d8917..fc2090b 100644
--- a/chrome/browser/resources/md_extensions/manager.html
+++ b/chrome/browser/resources/md_extensions/manager.html
@@ -63,7 +63,7 @@
       </extensions-toolbar>
       <dialog id="drawer" is="cr-drawer" heading="$i18n{toolbarTitle}">
         <div class="drawer-content">
-          <extensions-sidebar></extensions-sidebar>
+          <extensions-sidebar id="sidebar"></extensions-sidebar>
         </div>
       </dialog>
       <extensions-view-manager id="viewManager">
diff --git a/chrome/browser/resources/md_extensions/manager.js b/chrome/browser/resources/md_extensions/manager.js
index c6d969e5..675a8eb 100644
--- a/chrome/browser/resources/md_extensions/manager.js
+++ b/chrome/browser/resources/md_extensions/manager.js
@@ -72,12 +72,6 @@
        */
       detailViewItem_: Object,
 
-      /**
-       * The helper object to maintain page state.
-       * @private {!extensions.NavigationHelper}
-       */
-      navigationHelper_: Object,
-
       /** @type {!Array<!chrome.developerPrivate.ExtensionInfo>} */
       extensions: {
         type: Array,
@@ -129,15 +123,10 @@
     },
 
     ready: function() {
-      /** @type {extensions.Sidebar} */
-      this.sidebar =
-          /** @type {extensions.Sidebar} */ (this.$$('extensions-sidebar'));
       this.toolbar =
           /** @type {extensions.Toolbar} */ (this.$$('extensions-toolbar'));
-      this.listHelper_ = new ListHelper(this);
-      this.sidebar.setListDelegate(this.listHelper_);
       this.readyPromiseResolver.resolve();
-      this.navigationHelper_ = new extensions.NavigationHelper(newPage => {
+      extensions.navigation.onRouteChanged(newPage => {
         this.changePage(newPage, true);
       });
     },
@@ -168,7 +157,7 @@
      */
     initPage: function() {
       this.didInitPage_ = true;
-      this.changePage(this.navigationHelper_.getCurrentPage(), true);
+      this.changePage(extensions.navigation.getCurrentPage(), true);
     },
 
     /**
@@ -316,6 +305,8 @@
      *     of the change.
      */
     changePage: function(newPage, isSilent) {
+      // TODO(scottchen): Remove this once all calls go through
+      // extensions.navigateTo.
       if (this.currentPage_ && this.currentPage_.page == newPage.page &&
           this.currentPage_.type == newPage.type &&
           this.currentPage_.subpage == newPage.subpage &&
@@ -357,8 +348,10 @@
 
       this.currentPage_ = newPage;
 
+      // TODO(scottchen): Remove this once all calls go through
+      // extensions.navigateTo.
       if (!isSilent)
-        this.navigationHelper_.updateHistory(newPage);
+        extensions.navigation.updateHistory(newPage);
     },
 
     /**
@@ -432,24 +425,5 @@
     }
   });
 
-  /** @implements {extensions.SidebarListDelegate} */
-  class ListHelper {
-    /** @param {extensions.Manager} manager */
-    constructor(manager) {
-      this.manager_ = manager;
-    }
-
-    /** @override */
-    showType(listType) {
-      let items;
-      this.manager_.changePage({page: Page.LIST, type: listType});
-    }
-
-    /** @override */
-    showKeyboardShortcuts() {
-      this.manager_.changePage({page: Page.SHORTCUTS});
-    }
-  }
-
   return {Manager: Manager};
 });
diff --git a/chrome/browser/resources/md_extensions/navigation_helper.js b/chrome/browser/resources/md_extensions/navigation_helper.js
index 4f058b4..768b9f1a 100644
--- a/chrome/browser/resources/md_extensions/navigation_helper.js
+++ b/chrome/browser/resources/md_extensions/navigation_helper.js
@@ -41,14 +41,12 @@
    * page), we use this object to manage the history and url conversions.
    */
   class NavigationHelper {
-    /**
-     * @param {!function(!PageState):void} onHistoryChange A function to call
-     *     when the page has changed as a result of the user going back or
-     *     forward in history; called with the new active page.
-     */
-    constructor(onHistoryChange) {
+    constructor() {
+      /** @private {!Array<function(!PageState)>} */
+      this.listeners_ = [];
+
       window.addEventListener('popstate', () => {
-        onHistoryChange(this.getCurrentPage());
+        this.notifyRouteChanged_(this.getCurrentPage());
       });
     }
 
@@ -78,6 +76,40 @@
     }
 
     /**
+     * Function to add subscribers.
+     * @param {!function(!PageState)} listener
+     */
+    onRouteChanged(listener) {
+      this.listeners_.push(listener);
+    }
+
+    /**
+     * Function to notify subscribers.
+     * @private
+     */
+    notifyRouteChanged_(newPage) {
+      for (const listener of this.listeners_) {
+        listener(newPage);
+      }
+    }
+
+    /**
+     * @param {!PageState} newPage the page to navigate to.
+     */
+    navigateTo(newPage) {
+      let currentPage = this.getCurrentPage();
+      if (currentPage && currentPage.page == newPage.page &&
+          currentPage.type == newPage.type &&
+          currentPage.subpage == newPage.subpage &&
+          currentPage.extensionId == newPage.extensionId) {
+        return;
+      }
+
+      this.updateHistory(newPage);
+      this.notifyRouteChanged_(newPage);
+    }
+
+    /**
      * Called when a page changes, and pushes state to history to reflect it.
      * @param {!PageState} entry
      */
@@ -109,7 +141,8 @@
       const state = {url: path};
       const currentPage = this.getCurrentPage();
       const isDialogNavigation = currentPage.page == entry.page &&
-          currentPage.extensionId == entry.extensionId;
+          currentPage.extensionId == entry.extensionId &&
+          currentPage.type == entry.type;
       // Navigating to a dialog doesn't visually change pages; it just opens
       // a dialog. As such, we replace state rather than pushing a new state
       // on the stack so that hitting the back button doesn't just toggle the
@@ -121,5 +154,9 @@
     }
   }
 
-  return {NavigationHelper: NavigationHelper};
+  const navigation = new NavigationHelper();
+
+  return {
+    navigation: navigation,
+  };
 });
diff --git a/chrome/browser/resources/md_extensions/sidebar.js b/chrome/browser/resources/md_extensions/sidebar.js
index cd1cd9c..c81d919 100644
--- a/chrome/browser/resources/md_extensions/sidebar.js
+++ b/chrome/browser/resources/md_extensions/sidebar.js
@@ -2,49 +2,28 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 cr.define('extensions', function() {
-  /** @interface */
-  const SidebarListDelegate = function() {};
-
-  SidebarListDelegate.prototype = {
-    /**
-     * Shows the given type of item.
-     * @param {extensions.ShowingType} type
-     */
-    showType: assertNotReached,
-
-    /** Shows the keyboard shortcuts page. */
-    showKeyboardShortcuts: assertNotReached,
-  };
-
   const Sidebar = Polymer({
     is: 'extensions-sidebar',
 
     behaviors: [I18nBehavior],
 
-    /** @param {extensions.SidebarListDelegate} listDelegate */
-    setListDelegate: function(listDelegate) {
-      /** @private {extensions.SidebarListDelegate} */
-      this.listDelegate_ = listDelegate;
-    },
-
     /** @private */
     onExtensionsTap_: function() {
-      this.listDelegate_.showType(extensions.ShowingType.EXTENSIONS);
+      extensions.navigation.navigateTo(
+          {page: Page.LIST, type: extensions.ShowingType.EXTENSIONS});
     },
 
     /** @private */
     onAppsTap_: function() {
-      this.listDelegate_.showType(extensions.ShowingType.APPS);
+      extensions.navigation.navigateTo(
+          {page: Page.LIST, type: extensions.ShowingType.APPS});
     },
 
     /** @private */
     onKeyboardShortcutsTap_: function() {
-      this.listDelegate_.showKeyboardShortcuts();
+      extensions.navigation.navigateTo({page: Page.SHORTCUTS});
     },
   });
 
-  return {
-    Sidebar: Sidebar,
-    SidebarListDelegate: SidebarListDelegate,
-  };
+  return {Sidebar: Sidebar};
 });
diff --git a/chrome/browser/resources/net_internals/import_view.html b/chrome/browser/resources/net_internals/import_view.html
index 1f91f12..9c5e704 100644
--- a/chrome/browser/resources/net_internals/import_view.html
+++ b/chrome/browser/resources/net_internals/import_view.html
@@ -35,7 +35,7 @@
 <div id=import-view-tab-content class=content-box>
   <div>
     <div style='margin-bottom:20px'><b>TIP</b>: Drag-and-drop files into this window.</div>
-    <input type=file value="Load log from file" id=import-view-load-log-file accept=".json"></input>
+    <input type=file value="Load log from file" id=import-view-load-log-file accept=".json">
     <pre id=import-view-load-status-text></pre>
   </div>
 
diff --git a/chrome/browser/resources/policy.html b/chrome/browser/resources/policy.html
index 96f3e7b..480bdc9d 100644
--- a/chrome/browser/resources/policy.html
+++ b/chrome/browser/resources/policy.html
@@ -23,7 +23,6 @@
       <input id="filter" class="search-field-container" type="search"
           i18n-values="placeholder:filterPlaceholder;
                        aria-label:filterPlaceholder" incremental>
-      </input>
     </header>
   </div>
   <div class="page">
@@ -44,7 +43,7 @@
       </div>
       <div id="show-unset-container" class="show-unset-checkbox">
         <label>
-          <input id="show-unset" type="checkbox"></input>
+          <input id="show-unset" type="checkbox">
           <span i18n-content="showUnset"></span>
         </label>
       </div>
diff --git a/chrome/browser/resources/print_preview/settings/advanced_settings/advanced_settings_item.html b/chrome/browser/resources/print_preview/settings/advanced_settings/advanced_settings_item.html
index e315a404..da8415d 100644
--- a/chrome/browser/resources/print_preview/settings/advanced_settings/advanced_settings_item.html
+++ b/chrome/browser/resources/print_preview/settings/advanced_settings/advanced_settings_item.html
@@ -7,7 +7,6 @@
       </span>
       <span class="advanced-settings-item-value-text" hidden>
         <input type="text" class="advanced-settings-item-value-text-control">
-        </input>
       </span>
     </span>
 </div>
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/password_list_item.html b/chrome/browser/resources/settings/passwords_and_forms_page/password_list_item.html
index 7d48f74..2bde5b23 100644
--- a/chrome/browser/resources/settings/passwords_and_forms_page/password_list_item.html
+++ b/chrome/browser/resources/settings/passwords_and_forms_page/password_list_item.html
@@ -51,7 +51,6 @@
               on-tap="onReadonlyInputTap_" class="password-field" readonly
               disabled$="[[!password]]"
               value="[[getPassword_(item, password)]]">
-          </input>
           <button is="paper-icon-button-light" id="showPasswordButton"
               class$="[[getIconClass_(item, password)]]"
               on-tap="onShowPasswordButtonTap_"
diff --git a/chrome/browser/resources/settings/people_page/people_page.html b/chrome/browser/resources/settings/people_page/people_page.html
index 3490058..bcb99fcf 100644
--- a/chrome/browser/resources/settings/people_page/people_page.html
+++ b/chrome/browser/resources/settings/people_page/people_page.html
@@ -86,11 +86,17 @@
       }
 
       .delete-profile-warning {
+        -webkit-padding-end: var(--cr-section-padding);
         /* In order to line up with the checkbox text. */
-        -webkit-padding-start: 36px;
+        -webkit-padding-start: var(--cr-section-indent-padding);
         padding-bottom: 10px;
         padding-top: 10px;
       }
+
+      #wideFooter {
+        /* Override the cr-dialog footer padding. */
+        padding: 16px 0;
+      }
     </style>
     <settings-animated-pages id="pages" section="people"
         focus-config="[[focusConfig_]]">
@@ -317,7 +323,7 @@
         </div>
 <if expr="(not chromeos and is_posix) or is_win or is_macosx">
         <template is="dom-if" if="[[!syncStatus.domain]]">
-          <div slot="footer">
+          <div id="wideFooter" slot="footer">
             <div class="settings-box first">
               <paper-checkbox id="deleteProfile" class="start"
                   checked="{{deleteProfile_}}">
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.html b/chrome/browser/resources/settings/privacy_page/privacy_page.html
index fcd85c0..9485e7c 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_page.html
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page.html
@@ -262,10 +262,26 @@
               label="$i18n{thirdPartyCookie}"
               sub-label="$i18n{thirdPartyCookieSublabel}">
           </settings-toggle-button>
+          <div class="settings-box" actionable on-tap="onSiteDataTap_">
+             <div class="start" id="cookiesLink">
+               $i18n{siteSettingsCookieLink}
+             </div>
+             <button class="subpage-arrow" is="paper-icon-button-light"
+                 aria-labelledby="cookiesLink">
+             </button>
+          </div>
           <category-setting-exceptions
               category="{{ContentSettingsTypes.COOKIES}}">
           </category-setting-exceptions>
-          <site-data focus-config="[[focusConfig_]]"></site-data>
+        </settings-subpage>
+      </template>
+      <template is="dom-if" route-path="/siteData" no-search>
+        <settings-subpage page-title="$i18n{siteSettingsCookieHeader}"
+            search-label="$i18n{siteSettingsCookieSearch}"
+            search-term="{{siteDataFilter_}}">
+          <site-data filter="[[siteDataFilter_]]"
+              focus-config="[[focusConfig_]]">
+          </site-data>
         </settings-subpage>
       </template>
       <template is="dom-if" route-path="/content/images" no-search>
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.js b/chrome/browser/resources/settings/privacy_page/privacy_page.js
index 5a8b67e..cb15fd0 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_page.js
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page.js
@@ -253,6 +253,11 @@
   },
 
   /** @private */
+  onSiteDataTap_: function() {
+    settings.navigateTo(settings.routes.SITE_SETTINGS_SITE_DATA);
+  },
+
+  /** @private */
   onSiteSettingsTap_: function() {
     settings.navigateTo(settings.routes.SITE_SETTINGS);
   },
diff --git a/chrome/browser/resources/settings/route.js b/chrome/browser/resources/settings/route.js
index e41e1fa..0892d59c 100644
--- a/chrome/browser/resources/settings/route.js
+++ b/chrome/browser/resources/settings/route.js
@@ -79,6 +79,7 @@
  *   SITE_SETTINGS_PDF_DOCUMENTS: (undefined|!settings.Route),
  *   SITE_SETTINGS_POPUPS: (undefined|!settings.Route),
  *   SITE_SETTINGS_PROTECTED_CONTENT: (undefined|!settings.Route),
+ *   SITE_SETTINGS_SITE_DATA: (undefined|!settings.Route),
  *   SITE_SETTINGS_SITE_DETAILS: (undefined|!settings.Route),
  *   SITE_SETTINGS_UNSANDBOXED_PLUGINS: (undefined|!settings.Route),
  *   SITE_SETTINGS_USB_DEVICES: (undefined|!settings.Route),
@@ -263,7 +264,7 @@
     r.POWER = r.DEVICE.createChild('/power');
     // </if>
 
-    // Advacned Routes
+    // Advanced Routes
     if (pageVisibility.advancedSettings !== false) {
       r.ADVANCED = new Route('/advanced');
 
@@ -299,8 +300,10 @@
           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_SITE_DATA =
+          r.SITE_SETTINGS_COOKIES.createChild('/siteData');
       r.SITE_SETTINGS_DATA_DETAILS =
-          r.SITE_SETTINGS_COOKIES.createChild('/cookies/detail');
+          r.SITE_SETTINGS_SITE_DATA.createChild('/cookies/detail');
       r.SITE_SETTINGS_IMAGES = r.SITE_SETTINGS.createChild('images');
       r.SITE_SETTINGS_JAVASCRIPT = r.SITE_SETTINGS.createChild('javascript');
       r.SITE_SETTINGS_SOUND = r.SITE_SETTINGS.createChild('sound');
diff --git a/chrome/browser/resources/settings/settings_vars_css.html b/chrome/browser/resources/settings/settings_vars_css.html
index aab22b0..b8d21f2c 100644
--- a/chrome/browser/resources/settings/settings_vars_css.html
+++ b/chrome/browser/resources/settings/settings_vars_css.html
@@ -15,9 +15,8 @@
     --settings-actionable: var(--cr-actionable);
 
     --settings-box-row-padding: var(--cr-section-padding);
-    --settings-box-row-indent: calc(
-        var(--settings-box-row-padding) + var(--settings-indent-width));
-    --settings-indent-width: 40px;
+    --settings-box-row-indent: var(--cr-section-indent-padding);
+    --settings-indent-width: var(--cr-section-indent-width);
     --settings-card-max-width: 680px;
     --settings-disabled-opacity: .65;
     --settings-error-color: var(--paper-red-700);
diff --git a/chrome/browser/resources/settings/site_settings/site_data.html b/chrome/browser/resources/settings/site_settings/site_data.html
index 41689b7..eb8408f3 100644
--- a/chrome/browser/resources/settings/site_settings/site_data.html
+++ b/chrome/browser/resources/settings/site_settings/site_data.html
@@ -15,6 +15,10 @@
 <dom-module id="site-data">
   <template>
     <style include="settings-shared">
+      [first] {
+        border-top: none;
+      }
+
       #removeShowingSites {
         -webkit-margin-start: auto;
       }
@@ -22,48 +26,35 @@
       #removeSecondary {
         -webkit-padding-start: 0;
       }
-
-      .subtitle-row {
-        margin-top: 9px;  /* With 15px in sub-items == 24px total margin. */
-      }
     </style>
-    <div class="settings-box first subtitle-row">
-      <div class="start">
-        <h2>$i18n{siteSettingsCookieHeader}</h2>
-      </div>
-      <settings-subpage-search id="filter" on-search-changed="onSearchChanged_"
-          label="$i18n{siteSettingsCookieSearch}">
-      </settings-subpage-search>
-    </div>
     <div class="settings-box continuation">
       <paper-button class="secondary-button" id="removeShowingSites"
           on-tap="onRemoveShowingSitesTap_"
           hidden$="[[!isRemoveButtonVisible_(sites, renderedItemCount)]]">
-        [[computeRemoveLabel_(filterString_)]]
+        [[computeRemoveLabel_(filter)]]
       </paper-button>
     </div>
-    <div class="list-frame vertical-list">
-      <template is="dom-repeat" id="list" items="[[sites]]" filter="showItem_"
-          rendered-item-count="{{renderedItemCount::dom-change}}"
-          notify-dom-change>
-        <div class="list-item two-line" on-tap="onSiteTap_" actionable>
-          <div class="favicon-image" style$="[[computeSiteIcon(item.site)]]">
-          </div>
-          <div class="middle">
-            [[item.site]]
-            <div class="secondary" id="siteSecondary">[[item.localData]]</div>
-          </div>
-          <button class="subpage-arrow" is="paper-icon-button-light"
-              aria-label$="[[item.site]]"
-              aria-describedby="siteSecondary"></button>
-          <div class="separator" id="removeSecondary"></div>
-          <button is="paper-icon-button-light" class="icon-delete-gray"
-              title$="[[i18n('siteSettingsCookieRemoveSite', item.site)]]"
-              on-tap="onRemoveSiteTap_">
-          </button>
+    <template is="dom-repeat" id="list" items="[[sites]]" filter="showItem_"
+        rendered-item-count="{{renderedItemCount::dom-change}}"
+        notify-dom-change>
+      <div class="settings-box two-line" first$="[[!index]]" id="siteItem"
+          on-tap="onSiteTap_" actionable>
+        <div class="favicon-image" style$="[[computeSiteIcon(item.site)]]">
         </div>
-      </template>
-    </div>
+        <div class="middle">
+          [[item.site]]
+          <div class="secondary" id="siteSecondary">[[item.localData]]</div>
+        </div>
+        <button class="subpage-arrow" is="paper-icon-button-light"
+            aria-label$="[[item.site]]"
+            aria-describedby="siteSecondary"></button>
+        <div class="separator" id="removeSecondary"></div>
+        <button is="paper-icon-button-light" class="icon-delete-gray"
+            title$="[[i18n('siteSettingsCookieRemoveSite', item.site)]]"
+            on-tap="onRemoveSiteTap_">
+        </button>
+      </div>
+    </template>
 
     <!-- Confirm Delete dialog -->
     <dialog is="cr-dialog" id="confirmDeleteDialog" close-text="$i18n{close}"
diff --git a/chrome/browser/resources/settings/site_settings/site_data.js b/chrome/browser/resources/settings/site_settings/site_data.js
index 9d70fea..d199c4b 100644
--- a/chrome/browser/resources/settings/site_settings/site_data.js
+++ b/chrome/browser/resources/settings/site_settings/site_data.js
@@ -20,14 +20,17 @@
 Polymer({
   is: 'site-data',
 
-  behaviors: [CookieTreeBehavior, I18nBehavior, settings.RouteObserverBehavior],
+  behaviors: [
+    CookieTreeBehavior,
+  ],
 
   properties: {
     /**
      * The current filter applied to the cookie data list.
-     * @private
      */
-    filterString_: {
+    filter: {
+      observer: 'onSearchChanged_',
+      notify: true,
       type: String,
       value: '',
     },
@@ -42,6 +45,11 @@
     },
   },
 
+  /** @override */
+  ready: function() {
+    this.loadCookies();
+  },
+
   /**
    * @param {!Map<string, string>} newConfig
    * @param {?Map<string, string>} oldConfig
@@ -63,33 +71,19 @@
   },
 
   /**
-   * Reload cookies when the cookie page is visited.
-   *
-   * settings.RouteObserverBehavior
-   * @param {!settings.Route} currentRoute
-   * @protected
-   */
-  currentRouteChanged: function(currentRoute) {
-    if (currentRoute == settings.routes.SITE_SETTINGS_COOKIES) {
-      this.loadCookies();
-    }
-  },
-
-  /**
    * A filter function for the list.
    * @param {!CookieDataSummaryItem} item The item to possibly filter out.
    * @return {boolean} Whether to show the item.
    * @private
    */
   showItem_: function(item) {
-    if (this.filterString_.length == 0)
+    if (this.filter.length == 0)
       return true;
-    return item.site.indexOf(this.filterString_) > -1;
+    return item.site.indexOf(this.filter) > -1;
   },
 
   /** @private */
-  onSearchChanged_: function(e) {
-    this.filterString_ = e.detail;
+  onSearchChanged_: function() {
     this.$.list.render();
   },
 
@@ -103,11 +97,11 @@
 
   /**
    * Returns the string to use for the Remove label.
-   * @return {string} filterString The current filter string.
+   * @return {string} filter The current filter string.
    * @private
    */
-  computeRemoveLabel_: function(filterString) {
-    if (filterString.length == 0)
+  computeRemoveLabel_: function(filter) {
+    if (filter.length == 0)
       return loadTimeData.getString('siteSettingsCookieRemoveAll');
     return loadTimeData.getString('siteSettingsCookieRemoveAllShown');
   },
@@ -141,7 +135,7 @@
   onConfirmDelete_: function() {
     this.$.confirmDeleteDialog.close();
 
-    if (this.filterString_.length == 0) {
+    if (this.filter.length == 0) {
       this.removeAllCookies();
     } else {
       var items = this.$.list.items;
diff --git a/chrome/browser/resources/settings/site_settings/site_data_details_subpage.html b/chrome/browser/resources/settings/site_settings/site_data_details_subpage.html
index 2006306..7ab3d55 100644
--- a/chrome/browser/resources/settings/site_settings/site_data_details_subpage.html
+++ b/chrome/browser/resources/settings/site_settings/site_data_details_subpage.html
@@ -26,6 +26,7 @@
         <div class="start">[[getEntryDescription_(item)]]</div>
         <cr-expand-button expanded="{{item.expanded_}}">
         </cr-expand-button>
+        <div class="separator"></div>
         <button is="paper-icon-button-light" data-id-path$="[[item.idPath]]"
             class="icon-clear" on-tap="onRemove_">
         </button>
diff --git a/chrome/browser/search_engines/ui_thread_search_terms_data.h b/chrome/browser/search_engines/ui_thread_search_terms_data.h
index adf4953..551f6a0e 100644
--- a/chrome/browser/search_engines/ui_thread_search_terms_data.h
+++ b/chrome/browser/search_engines/ui_thread_search_terms_data.h
@@ -33,6 +33,7 @@
 
 #if defined(OS_ANDROID)
   std::string GetYandexReferralID() const override;
+  std::string GetMailRUReferralID() const override;
 #endif
 
   // Used by tests to override the value for the Google base URL.  Passing the
diff --git a/chrome/browser/search_engines/ui_thread_search_terms_data_android.cc b/chrome/browser/search_engines/ui_thread_search_terms_data_android.cc
index 6f9bfb4..a2023d1 100644
--- a/chrome/browser/search_engines/ui_thread_search_terms_data_android.cc
+++ b/chrome/browser/search_engines/ui_thread_search_terms_data_android.cc
@@ -33,3 +33,7 @@
 std::string UIThreadSearchTermsData::GetYandexReferralID() const {
   return LocaleManager::GetYandexReferralID();
 }
+
+std::string UIThreadSearchTermsData::GetMailRUReferralID() const {
+  return LocaleManager::GetMailRUReferralID();
+}
diff --git a/chrome/browser/signin/easy_unlock_service_signin_chromeos.cc b/chrome/browser/signin/easy_unlock_service_signin_chromeos.cc
index 3d1ae8e9..b01b4d57 100644
--- a/chrome/browser/signin/easy_unlock_service_signin_chromeos.cc
+++ b/chrome/browser/signin/easy_unlock_service_signin_chromeos.cc
@@ -540,7 +540,7 @@
 
   cryptauth::RemoteDeviceList remote_devices;
   for (const auto& device : devices) {
-    std::string decoded_public_key, decoded_psk, decoded_challenge;
+    std::string decoded_public_key, decoded_psk;
     if (!base::Base64UrlDecode(device.public_key,
                                base::Base64UrlDecodePolicy::REQUIRE_PADDING,
                                &decoded_public_key) ||
@@ -552,9 +552,14 @@
                     << "  psk: " << device.psk;
       continue;
     }
+    // TODO(tengs): We assume that the device is an unlock key since we only
+    // request unlock keys for EasyUnlock. Instead, we should include bool
+    // (as well as the "supports_mobile_hotspot" bool) as part of
+    // EasyUnlockDeviceKeyData instead of making that assumption here.
     cryptauth::RemoteDevice remote_device(
         account_id.GetUserEmail(), std::string(), decoded_public_key,
-        device.bluetooth_address, decoded_psk, decoded_challenge);
+        device.bluetooth_address, decoded_psk, true /* unlock_key */,
+        false /* supports_mobile_hotspot */);
 
     if (!device.serialized_beacon_seeds.empty()) {
       PA_LOG(INFO) << "Deserializing BeaconSeeds: "
diff --git a/chrome/browser/ssl/ssl_browser_tests.cc b/chrome/browser/ssl/ssl_browser_tests.cc
index 07ce57af..a30a08d2 100644
--- a/chrome/browser/ssl/ssl_browser_tests.cc
+++ b/chrome/browser/ssl/ssl_browser_tests.cc
@@ -5669,7 +5669,8 @@
 
 // Tests that the correct strings are displayed on the interstitial in the
 // enterprise managed case.
-IN_PROC_BROWSER_TEST_F(SSLUIMITMSoftwareTest, EnterpriseManaged) {
+// Disabled the test per crbug.com/760438
+IN_PROC_BROWSER_TEST_F(SSLUIMITMSoftwareTest, DISABLED_EnterpriseManaged) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitFromCommandLine(
       "MITMSoftwareInterstitial" /* enabled */, std::string() /* disabled */);
@@ -5701,7 +5702,8 @@
 
 // Tests that the correct strings are displayed on the interstitial in the
 // non-enterprise managed case.
-IN_PROC_BROWSER_TEST_F(SSLUIMITMSoftwareTest, NotEnterpriseManaged) {
+// Disabled the test per crbug.com/760438
+IN_PROC_BROWSER_TEST_F(SSLUIMITMSoftwareTest, DISABLED_NotEnterpriseManaged) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitFromCommandLine(
       "MITMSoftwareInterstitial" /* enabled */, std::string() /* disabled */);
diff --git a/chrome/browser/ui/ash/app_list/app_list_presenter_service.cc b/chrome/browser/ui/ash/app_list/app_list_presenter_service.cc
index 828b8102..f456a0e5 100644
--- a/chrome/browser/ui/ash/app_list/app_list_presenter_service.cc
+++ b/chrome/browser/ui/ash/app_list/app_list_presenter_service.cc
@@ -69,10 +69,14 @@
 
 void AppListPresenterService::UpdateYPositionAndOpacity(
     int y_position_in_screen,
-    float background_opacity,
-    bool is_end_gesture) {
+    float background_opacity) {
   GetPresenter()->UpdateYPositionAndOpacity(y_position_in_screen,
-                                            background_opacity, is_end_gesture);
+                                            background_opacity);
+}
+
+void AppListPresenterService::EndDragFromShelf(
+    app_list::mojom::AppListState app_list_state) {
+  GetPresenter()->EndDragFromShelf(app_list_state);
 }
 
 app_list::AppListPresenterImpl* AppListPresenterService::GetPresenter() {
diff --git a/chrome/browser/ui/ash/app_list/app_list_presenter_service.h b/chrome/browser/ui/ash/app_list/app_list_presenter_service.h
index c7f1136..a373849 100644
--- a/chrome/browser/ui/ash/app_list/app_list_presenter_service.h
+++ b/chrome/browser/ui/ash/app_list/app_list_presenter_service.h
@@ -29,8 +29,8 @@
   void StartVoiceInteractionSession() override;
   void ToggleVoiceInteractionSession() override;
   void UpdateYPositionAndOpacity(int y_position_in_screen,
-                                 float background_opacity,
-                                 bool is_end_gesture) override;
+                                 float background_opacity) override;
+  void EndDragFromShelf(app_list::mojom::AppListState app_list_state) override;
 
  private:
   app_list::AppListPresenterImpl* GetPresenter();
diff --git a/chrome/browser/ui/ash/ash_init.cc b/chrome/browser/ui/ash/ash_init.cc
index 64fa94e..8d51414 100644
--- a/chrome/browser/ui/ash/ash_init.cc
+++ b/chrome/browser/ui/ash/ash_init.cc
@@ -98,12 +98,6 @@
   else
     CreateClassicShell();
 
-  ash::Shell* shell = ash::Shell::Get();
-
-  // Under mash the local state pref service isn't available until after shell
-  // initialization. Make classic ash behave the same way.
-  shell->SetLocalStatePrefService(g_browser_process->local_state());
-
   ash::AcceleratorControllerDelegateClassic* accelerator_controller_delegate =
       nullptr;
   if (chromeos::GetAshConfig() == ash::Config::CLASSIC) {
@@ -124,6 +118,7 @@
       base::CreateSequencedTaskRunnerWithTraits(
           {base::MayBlock(), base::TaskPriority::BACKGROUND,
            base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}));
+  ash::Shell* shell = ash::Shell::Get();
   shell->high_contrast_controller()->SetEnabled(
       chromeos::AccessibilityManager::Get()->IsHighContrastEnabled());
 
diff --git a/chrome/browser/ui/ash/ime_controller_client.cc b/chrome/browser/ui/ash/ime_controller_client.cc
index 8d9cdc6..26d9d01e 100644
--- a/chrome/browser/ui/ash/ime_controller_client.cc
+++ b/chrome/browser/ui/ash/ime_controller_client.cc
@@ -13,6 +13,7 @@
 #include "content/public/common/service_manager_connection.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "ui/base/ime/chromeos/extension_ime_util.h"
+#include "ui/base/ime/chromeos/ime_keyboard.h"
 #include "ui/base/ime/chromeos/input_method_descriptor.h"
 #include "ui/base/ime/chromeos/input_method_util.h"
 
@@ -32,6 +33,8 @@
   DCHECK(input_method_manager_);
   input_method_manager_->AddObserver(this);
   input_method_manager_->AddImeMenuObserver(this);
+  if (input_method_manager_->GetImeKeyboard())
+    input_method_manager_->GetImeKeyboard()->AddObserver(this);
   InputMethodMenuManager::GetInstance()->AddObserver(this);
 
   // This does not need to send the initial state to ash because that happens
@@ -48,6 +51,8 @@
   InputMethodMenuManager::GetInstance()->RemoveObserver(this);
   input_method_manager_->RemoveImeMenuObserver(this);
   input_method_manager_->RemoveObserver(this);
+  if (input_method_manager_->GetImeKeyboard())
+    input_method_manager_->GetImeKeyboard()->RemoveObserver(this);
 }
 
 void ImeControllerClient::Init() {
@@ -100,6 +105,13 @@
   input_method_manager_->ActivateInputMethodMenuItem(key);
 }
 
+void ImeControllerClient::SetCapsLockFromTray(bool caps_enabled) {
+  chromeos::input_method::ImeKeyboard* keyboard =
+      chromeos::input_method::InputMethodManager::Get()->GetImeKeyboard();
+  if (keyboard)
+    keyboard->SetCapsLockEnabled(caps_enabled);
+}
+
 // chromeos::input_method::InputMethodManager::Observer:
 void ImeControllerClient::InputMethodChanged(InputMethodManager* manager,
                                              Profile* profile,
@@ -126,6 +138,13 @@
   RefreshIme();
 }
 
+// chromeos::input_method::ImeKeyboard::Observer:
+void ImeControllerClient::OnCapsLockChanged(bool enabled) {
+  ime_controller_ptr_->SetCapsLockState(enabled);
+}
+
+void ImeControllerClient::OnLayoutChanging(const std::string& layout_name) {}
+
 void ImeControllerClient::FlushMojoForTesting() {
   ime_controller_ptr_.FlushForTesting();
 }
diff --git a/chrome/browser/ui/ash/ime_controller_client.h b/chrome/browser/ui/ash/ime_controller_client.h
index 18f4789b..fef4ace 100644
--- a/chrome/browser/ui/ash/ime_controller_client.h
+++ b/chrome/browser/ui/ash/ime_controller_client.h
@@ -9,6 +9,7 @@
 #include "ash/public/interfaces/ime_info.mojom.h"
 #include "base/macros.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "ui/base/ime/chromeos/ime_keyboard.h"
 #include "ui/base/ime/chromeos/input_method_manager.h"
 #include "ui/chromeos/ime/input_method_menu_manager.h"
 
@@ -17,6 +18,7 @@
     : public ash::mojom::ImeControllerClient,
       public chromeos::input_method::InputMethodManager::Observer,
       public chromeos::input_method::InputMethodManager::ImeMenuObserver,
+      public chromeos::input_method::ImeKeyboard::Observer,
       public ui::ime::InputMethodMenuManager::Observer {
  public:
   explicit ImeControllerClient(
@@ -39,6 +41,7 @@
   void SwitchToPreviousIme() override;
   void SwitchImeById(const std::string& id, bool show_message) override;
   void ActivateImeMenuItem(const std::string& key) override;
+  void SetCapsLockFromTray(bool caps_enabled) override;
 
   // chromeos::input_method::InputMethodManager::Observer:
   void InputMethodChanged(chromeos::input_method::InputMethodManager* manager,
@@ -57,6 +60,10 @@
   void InputMethodMenuItemChanged(
       ui::ime::InputMethodMenuManager* manager) override;
 
+  // chromeos::input_method::ImeKeyboard::Observer:
+  void OnCapsLockChanged(bool enabled) override;
+  void OnLayoutChanging(const std::string& layout_name) override;
+
   void FlushMojoForTesting();
 
  private:
diff --git a/chrome/browser/ui/ash/ime_controller_client_unittest.cc b/chrome/browser/ui/ash/ime_controller_client_unittest.cc
index 3043a47..da14502 100644
--- a/chrome/browser/ui/ash/ime_controller_client_unittest.cc
+++ b/chrome/browser/ui/ash/ime_controller_client_unittest.cc
@@ -169,6 +169,9 @@
   void ShowImeMenuOnShelf(bool show) override {
     show_ime_menu_on_shelf_ = show;
   }
+  void SetCapsLockState(bool enabled) override {
+    is_caps_lock_enabled_ = enabled;
+  }
 
   // The most recent values received via mojo.
   std::string current_ime_id_;
@@ -176,6 +179,7 @@
   std::vector<ash::mojom::ImeMenuItemPtr> menu_items_;
   bool managed_by_policy_ = false;
   bool show_ime_menu_on_shelf_ = false;
+  bool is_caps_lock_enabled_ = false;
 
  private:
   mojo::Binding<ash::mojom::ImeController> binding_;
@@ -224,6 +228,19 @@
   EXPECT_TRUE(ime_controller_.managed_by_policy_);
 }
 
+TEST_F(ImeControllerClientTest, CapsLock) {
+  ImeControllerClient client(&input_method_manager_);
+  client.InitForTesting(ime_controller_.CreateInterfacePtr());
+
+  client.OnCapsLockChanged(true);
+  client.FlushMojoForTesting();
+  EXPECT_TRUE(ime_controller_.is_caps_lock_enabled_);
+
+  client.OnCapsLockChanged(false);
+  client.FlushMojoForTesting();
+  EXPECT_FALSE(ime_controller_.is_caps_lock_enabled_);
+}
+
 TEST_F(ImeControllerClientTest, ShowImeMenuOnShelf) {
   ImeControllerClient client(&input_method_manager_);
   client.InitForTesting(ime_controller_.CreateInterfacePtr());
diff --git a/chrome/browser/ui/ash/session_controller_client.cc b/chrome/browser/ui/ash/session_controller_client.cc
index 5bef7eb..058a2c4 100644
--- a/chrome/browser/ui/ash/session_controller_client.cc
+++ b/chrome/browser/ui/ash/session_controller_client.cc
@@ -243,7 +243,7 @@
   }
 
   if (UserManager::Get()->GetLoggedInUsers().size() >=
-      session_manager::kMaxmiumNumberOfUserSessions) {
+      session_manager::kMaximumNumberOfUserSessions) {
     return;
   }
 
@@ -359,7 +359,7 @@
   }
 
   if (UserManager::Get()->GetLoggedInUsers().size() >=
-      session_manager::kMaxmiumNumberOfUserSessions)
+      session_manager::kMaximumNumberOfUserSessions)
     return ash::AddUserSessionPolicy::ERROR_MAXIMUM_USERS_REACHED;
 
   return ash::AddUserSessionPolicy::ALLOWED;
diff --git a/chrome/browser/ui/ash/session_controller_client_unittest.cc b/chrome/browser/ui/ash/session_controller_client_unittest.cc
index 0111157..583c09e 100644
--- a/chrome/browser/ui/ash/session_controller_client_unittest.cc
+++ b/chrome/browser/ui/ash/session_controller_client_unittest.cc
@@ -359,7 +359,7 @@
   const AccountId account_id(AccountId::FromUserEmail(kUser));
   user_manager()->LoginUser(account_id);
   while (user_manager()->GetLoggedInUsers().size() <
-         session_manager::kMaxmiumNumberOfUserSessions) {
+         session_manager::kMaximumNumberOfUserSessions) {
     UserAddedToSession("bb@b.b");
   }
   EXPECT_EQ(ash::AddUserSessionPolicy::ERROR_MAXIMUM_USERS_REACHED,
diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc
index 1a830a5..3fd7f39 100644
--- a/chrome/browser/ui/browser_browsertest.cc
+++ b/chrome/browser/ui/browser_browsertest.cc
@@ -485,9 +485,8 @@
   EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
 }
 
-#if defined(OS_WIN)
+#if defined(OS_WIN) && !defined(NDEBUG)
 // http://crbug.com/114859. Times out frequently on Windows.
-// https://crbug.com/757836. Flakily runs out of memory on Windows.
 #define MAYBE_ThirtyFourTabs DISABLED_ThirtyFourTabs
 #else
 #define MAYBE_ThirtyFourTabs ThirtyFourTabs
diff --git a/chrome/browser/ui/browser_command_controller_interactive_browsertest.cc b/chrome/browser/ui/browser_command_controller_interactive_browsertest.cc
index a0dc7b7..9fcc2ada 100644
--- a/chrome/browser/ui/browser_command_controller_interactive_browsertest.cc
+++ b/chrome/browser/ui/browser_command_controller_interactive_browsertest.cc
@@ -552,9 +552,8 @@
 // the page to exit fullscreen mode. So we need to maintain a list of exiting /
 // non-exiting commands, which is not the goal of this test.
 
-#if defined(OS_CHROMEOS) || defined(OS_LINUX)
-// This test is flaky on ChromeOS and Linux, see bugs http://crbug.com/754878
-// and http://crbug.com/759704.
+#if defined(OS_CHROMEOS)
+// This test is flaky on ChromeOS, see http://crbug.com/754878.
 #define MAYBE_ShortcutsShouldTakeEffectInJsFullscreen \
         DISABLED_ShortcutsShouldTakeEffectInJsFullscreen
 #else
@@ -563,6 +562,13 @@
 #endif
 IN_PROC_BROWSER_TEST_F(BrowserCommandControllerInteractiveTest,
                        MAYBE_ShortcutsShouldTakeEffectInJsFullscreen) {
+  // This test is flaky when browser side navigation is enabled on Linux. See
+  // http://crbug.com/759704.
+  // TODO(zijiehe): Find out the root cause.
+#if defined(OS_LINUX)
+  if (content::IsBrowserSideNavigationEnabled())
+    return;
+#endif
   ASSERT_NO_FATAL_FAILURE(SendShortcutsAndExpectNotPrevented(true));
 }
 
diff --git a/chrome/browser/ui/cocoa/page_info/page_info_bubble_controller.h b/chrome/browser/ui/cocoa/page_info/page_info_bubble_controller.h
index e4406b9..b3875f5c 100644
--- a/chrome/browser/ui/cocoa/page_info/page_info_bubble_controller.h
+++ b/chrome/browser/ui/cocoa/page_info/page_info_bubble_controller.h
@@ -102,6 +102,14 @@
   // info icon has a race condition where it might switch between
   // LocationIconDecoration and SecurityStateBubbleDecoration.
   LocationBarDecoration* decoration_;  // Weak.
+
+  // The button for changing password decisions.
+  // This button only shows when there is an password reuse event.
+  NSButton* changePasswordButton_;
+
+  // The button for whitelisting password reuse decisions.
+  // This button only shows when there is an password reuse event.
+  NSButton* whitelistPasswordReuseButton_;
 }
 
 // Designated initializer. The controller will release itself when the bubble
diff --git a/chrome/browser/ui/cocoa/page_info/page_info_bubble_controller.mm b/chrome/browser/ui/cocoa/page_info/page_info_bubble_controller.mm
index 6d223c1..f101151 100644
--- a/chrome/browser/ui/cocoa/page_info/page_info_bubble_controller.mm
+++ b/chrome/browser/ui/cocoa/page_info/page_info_bubble_controller.mm
@@ -22,6 +22,7 @@
 #include "chrome/browser/ui/cocoa/bubble_anchor_helper.h"
 #import "chrome/browser/ui/cocoa/info_bubble_view.h"
 #import "chrome/browser/ui/cocoa/info_bubble_window.h"
+#include "chrome/browser/ui/cocoa/key_equivalent_constants.h"
 #import "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h"
 #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
 #import "chrome/browser/ui/cocoa/page_info/permission_selector_button.h"
@@ -42,6 +43,7 @@
 #import "third_party/google_toolbox_for_mac/src/AppKit/GTMUILocalizerAndLayoutTweaker.h"
 #import "ui/base/cocoa/a11y_util.h"
 #include "ui/base/cocoa/cocoa_base_utils.h"
+#import "ui/base/cocoa/controls/button_utils.h"
 #import "ui/base/cocoa/controls/hyperlink_button_cell.h"
 #import "ui/base/cocoa/flipped_view.h"
 #import "ui/base/cocoa/hover_image_button.h"
@@ -397,6 +399,8 @@
   // These will be created only if necessary.
   resetDecisionsField_ = nil;
   resetDecisionsButton_ = nil;
+  changePasswordButton_ = nil;
+  whitelistPasswordReuseButton_ = nil;
 
   NSString* connectionHelpButtonText = l10n_util::GetNSString(IDS_LEARN_MORE);
   connectionHelpButton_ = [self addLinkButtonWithText:connectionHelpButtonText
@@ -569,6 +573,20 @@
   [self close];
 }
 
+// Handler for the button to change password decisions.
+- (void)changePasswordDecisions:(id)sender {
+  DCHECK(changePasswordButton_);
+  presenter_->OnChangePasswordButtonPressed(webContents_);
+  [self close];
+}
+
+// Handler for the button to whitelist password reuse decisions.
+- (void)whitelistPasswordReuseDecisions:(id)sender {
+  DCHECK(whitelistPasswordReuseButton_);
+  presenter_->OnWhitelistPasswordReuseButtonPressed(webContents_);
+  [self close];
+}
+
 - (CGFloat)layoutViewAtRTLStart:(NSView*)view withYPosition:(CGFloat)yPos {
   CGFloat xPos;
   if (base::i18n::IsRTL()) {
@@ -658,6 +676,41 @@
     yPos = NSMaxY([resetDecisionsButton_ frame]);
   }
 
+  if (changePasswordButton_) {
+    NSPoint changePasswordButtonOrigin;
+    NSPoint whitelistReuseButtonOrigin;
+    bool canFitInOneLine = NSWidth([changePasswordButton_ frame]) +
+                               NSWidth([whitelistPasswordReuseButton_ frame]) +
+                               kNSButtonBuiltinMargin <=
+                           NSWidth([contentView_ frame]);
+    bool isRTL = base::i18n::IsRTL();
+    CGFloat horizontalPadding =
+        kSectionHorizontalPadding - kNSButtonBuiltinMargin;
+    changePasswordButtonOrigin.x =
+        isRTL ? NSWidth([contentView_ frame]) -
+                    NSWidth([changePasswordButton_ frame]) - horizontalPadding
+              : horizontalPadding;
+    changePasswordButtonOrigin.y = yPos + kSecurityParagraphSpacing;
+    whitelistReuseButtonOrigin.x =
+        isRTL ? (canFitInOneLine
+                     ? changePasswordButtonOrigin.x - kNSButtonBuiltinMargin -
+                           NSWidth([whitelistPasswordReuseButton_ frame])
+                     : NSWidth([contentView_ frame]) -
+                           NSWidth([whitelistPasswordReuseButton_ frame]) -
+                           horizontalPadding)
+              : (canFitInOneLine ? changePasswordButtonOrigin.x +
+                                       NSWidth([changePasswordButton_ frame]) +
+                                       kNSButtonBuiltinMargin
+                                 : changePasswordButtonOrigin.x);
+    whitelistReuseButtonOrigin.y =
+        canFitInOneLine ? changePasswordButtonOrigin.y
+                        : yPos + NSHeight([changePasswordButton_ frame]);
+    [changePasswordButton_ setFrameOrigin:changePasswordButtonOrigin];
+    [whitelistPasswordReuseButton_ setFrameOrigin:whitelistReuseButtonOrigin];
+    yPos =
+        NSMaxY([whitelistPasswordReuseButton_ frame]) - kNSButtonBuiltinMargin;
+  }
+
   // Resize the height based on contents.
   [self setHeightOfView:securitySectionView_ to:yPos + kSectionVerticalPadding];
 }
@@ -825,7 +878,7 @@
 }
 
 // Set the content of the identity and identity status fields, and add the
-// Certificate view if applicable.
+// Certificate view or password reuse buttons if applicable.
 - (void)setIdentityInfo:(const PageInfoUI::IdentityInfo&)identityInfo {
   std::unique_ptr<PageInfoUI::SecurityDescription> security_description =
       identityInfo.GetSecurityDescription();
@@ -885,6 +938,23 @@
                            withAction:@selector(showCertificateInfo:)];
     }
   }
+  if (identityInfo.show_change_password_buttons) {
+    changePasswordButton_ =
+        [ButtonUtils buttonWithTitle:l10n_util::GetNSString(
+                                         IDS_PAGE_INFO_CHANGE_PASSWORD_BUTTON)
+                              action:@selector(changePasswordDecisions:)
+                              target:securitySectionView_];
+    [changePasswordButton_ sizeToFit];
+    [changePasswordButton_ setKeyEquivalent:kKeyEquivalentReturn];
+    [securitySectionView_ addSubview:changePasswordButton_];
+    whitelistPasswordReuseButton_ = [ButtonUtils
+        buttonWithTitle:l10n_util::GetNSString(
+                            IDS_PAGE_INFO_WHITELIST_PASSWORD_REUSE_BUTTON)
+                 action:@selector(whitelistPasswordReuseDecisions:)
+                 target:securitySectionView_];
+    [whitelistPasswordReuseButton_ sizeToFit];
+    [securitySectionView_ addSubview:whitelistPasswordReuseButton_];
+  }
 
   [self performLayout];
 }
diff --git a/chrome/browser/ui/cocoa/page_info/page_info_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/page_info/page_info_bubble_controller_unittest.mm
index 594c2da..afa6c65d 100644
--- a/chrome/browser/ui/cocoa/page_info/page_info_bubble_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/page_info/page_info_bubble_controller_unittest.mm
@@ -34,6 +34,12 @@
 - (NSButton*)connectionHelpButton {
   return connectionHelpButton_;
 }
+- (NSButton*)changePasswordButton {
+  return changePasswordButton_;
+}
+- (NSButton*)whitelistPasswordReuseButton {
+  return whitelistPasswordReuseButton_;
+}
 @end
 
 @interface PageInfoBubbleControllerForTesting : PageInfoBubbleController {
@@ -334,4 +340,30 @@
   EXPECT_FALSE(decoration->active());
 }
 
+TEST_F(PageInfoBubbleControllerTest, PasswordReuseButtons) {
+  PageInfoUI::IdentityInfo info;
+  info.site_identity = std::string("example.com");
+  info.identity_status = PageInfo::SITE_IDENTITY_STATUS_UNKNOWN;
+
+  CreateBubble();
+
+  // Set identity info, specifying that buttons should not be shown.
+  info.show_change_password_buttons = false;
+  bridge_->SetIdentityInfo(const_cast<PageInfoUI::IdentityInfo&>(info));
+  EXPECT_EQ([controller_ changePasswordButton], nil);
+  EXPECT_EQ([controller_ whitelistPasswordReuseButton], nil);
+
+  // Set identity info, specifying that buttons should be shown.
+  info.show_change_password_buttons = true;
+  bridge_->SetIdentityInfo(const_cast<PageInfoUI::IdentityInfo&>(info));
+  EXPECT_NE([controller_ changePasswordButton], nil);
+  EXPECT_NE([controller_ whitelistPasswordReuseButton], nil);
+
+  // Check that clicking the button calls the right selector.
+  EXPECT_EQ([[controller_ changePasswordButton] action],
+            @selector(changePasswordDecisions:));
+  EXPECT_EQ([[controller_ whitelistPasswordReuseButton] action],
+            @selector(whitelistPasswordReuseDecisions:));
+}
+
 }  // namespace
diff --git a/chrome/browser/ui/page_info/page_info.cc b/chrome/browser/ui/page_info/page_info.cc
index a4a4392..818288d6 100644
--- a/chrome/browser/ui/page_info/page_info.cc
+++ b/chrome/browser/ui/page_info/page_info.cc
@@ -241,7 +241,7 @@
           l10n_util::GetStringUTF16(IDS_PAGE_INFO_UNWANTED_SOFTWARE_DETAILS);
       break;
     case security_state::MALICIOUS_CONTENT_STATUS_PASSWORD_REUSE:
-#if defined(SAFE_BROWSING_DB_LOCAL) && !defined(OS_MACOSX)
+#if defined(SAFE_BROWSING_DB_LOCAL)
       *status = PageInfo::SITE_IDENTITY_STATUS_PASSWORD_REUSE;
       *details =
           l10n_util::GetStringUTF16(IDS_PAGE_INFO_CHANGE_PASSWORD_DETAILS);
@@ -291,11 +291,11 @@
       did_revoke_user_ssl_decisions_(false),
       profile_(profile),
       security_level_(security_state::NONE),
-#if defined(SAFE_BROWSING_DB_LOCAL) && !defined(OS_MACOSX)
+#if defined(SAFE_BROWSING_DB_LOCAL)
       password_protection_service_(nullptr),
 #endif
       show_change_password_buttons_(false) {
-#if defined(SAFE_BROWSING_DB_LOCAL) && !defined(OS_MACOSX)
+#if defined(SAFE_BROWSING_DB_LOCAL)
   safe_browsing::SafeBrowsingService* sb_service =
       g_browser_process->safe_browsing_service();
   if (sb_service && sb_service->enabled_by_prefs()) {
@@ -469,7 +469,7 @@
 
 void PageInfo::OnChangePasswordButtonPressed(
     content::WebContents* web_contents) {
-#if defined(SAFE_BROWSING_DB_LOCAL) && !defined(OS_MACOSX)
+#if defined(SAFE_BROWSING_DB_LOCAL)
   DCHECK(password_protection_service_);
   password_protection_service_->OnWarningDone(
       web_contents, safe_browsing::PasswordProtectionService::PAGE_INFO,
@@ -479,7 +479,7 @@
 
 void PageInfo::OnWhitelistPasswordReuseButtonPressed(
     content::WebContents* web_contents) {
-#if defined(SAFE_BROWSING_DB_LOCAL) && !defined(OS_MACOSX)
+#if defined(SAFE_BROWSING_DB_LOCAL)
   DCHECK(password_protection_service_);
   password_protection_service_->OnWarningDone(
       web_contents, safe_browsing::PasswordProtectionService::PAGE_INFO,
@@ -859,7 +859,7 @@
   info.show_ssl_decision_revoke_button = show_ssl_decision_revoke_button_;
   info.show_change_password_buttons = show_change_password_buttons_;
   ui_->SetIdentityInfo(info);
-#if defined(SAFE_BROWSING_DB_LOCAL) && !defined(OS_MACOSX)
+#if defined(SAFE_BROWSING_DB_LOCAL)
   if (password_protection_service_ && show_change_password_buttons_) {
     password_protection_service_->OnWarningShown(
         web_contents(), safe_browsing::PasswordProtectionService::PAGE_INFO);
diff --git a/chrome/browser/ui/page_info/page_info.h b/chrome/browser/ui/page_info/page_info.h
index 1205a6b..4ba5a41 100644
--- a/chrome/browser/ui/page_info/page_info.h
+++ b/chrome/browser/ui/page_info/page_info.h
@@ -254,7 +254,7 @@
 
   security_state::SecurityLevel security_level_;
 
-#if defined(SAFE_BROWSING_DB_LOCAL) && !defined(OS_MACOSX)
+#if defined(SAFE_BROWSING_DB_LOCAL)
   // Used to handle changing password, and whitelisting site.
   safe_browsing::PasswordProtectionService* password_protection_service_;
 #endif
diff --git a/chrome/browser/ui/page_info/page_info_ui.cc b/chrome/browser/ui/page_info/page_info_ui.cc
index 93c74bb..abed05193 100644
--- a/chrome/browser/ui/page_info/page_info_ui.cc
+++ b/chrome/browser/ui/page_info/page_info_ui.cc
@@ -35,7 +35,7 @@
 #include "ui/gfx/paint_vector_icon.h"
 #endif
 
-#if defined(SAFE_BROWSING_DB_LOCAL) && !defined(OS_MACOSX)
+#if defined(SAFE_BROWSING_DB_LOCAL)
 #include "components/safe_browsing/password_protection/password_protection_service.h"
 #endif
 
@@ -248,7 +248,7 @@
       return CreateSecurityDescription(IDS_PAGE_INFO_UNWANTED_SOFTWARE_SUMMARY,
                                        IDS_PAGE_INFO_UNWANTED_SOFTWARE_DETAILS);
     case PageInfo::SITE_IDENTITY_STATUS_PASSWORD_REUSE:
-#if defined(SAFE_BROWSING_DB_LOCAL) && !defined(OS_MACOSX)
+#if defined(SAFE_BROWSING_DB_LOCAL)
       return safe_browsing::PasswordProtectionService::ShouldShowSofterWarning()
                  ? CreateSecurityDescription(
                        IDS_PAGE_INFO_CHANGE_PASSWORD_SUMMARY_SOFTER,
diff --git a/chrome/browser/ui/page_info/page_info_unittest.cc b/chrome/browser/ui/page_info/page_info_unittest.cc
index 284f449b..e0e7a825 100644
--- a/chrome/browser/ui/page_info/page_info_unittest.cc
+++ b/chrome/browser/ui/page_info/page_info_unittest.cc
@@ -344,7 +344,7 @@
             page_info()->site_identity_status());
 }
 
-#if defined(SAFE_BROWSING_DB_LOCAL) && !defined(OS_MACOSX)
+#if defined(SAFE_BROWSING_DB_LOCAL)
 TEST_F(PageInfoTest, PasswordReuse) {
   security_info_.security_level = security_state::DANGEROUS;
   security_info_.malicious_content_status =
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.h b/chrome/browser/ui/views/location_bar/location_bar_view.h
index 3bc6e7ae..a3804788 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.h
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.h
@@ -180,6 +180,10 @@
 
   LocationIconView* location_icon_view() { return location_icon_view_; }
 
+  SelectedKeywordView* selected_keyword_view() {
+    return selected_keyword_view_;
+  }
+
   // Where InfoBar arrows should point. The point will be returned in the
   // coordinates of the LocationBarView.
   gfx::Point GetInfoBarAnchorPoint() const;
diff --git a/chrome/browser/ui/views/location_bar/selected_keyword_view.h b/chrome/browser/ui/views/location_bar/selected_keyword_view.h
index f87ec00..4cf52ab9 100644
--- a/chrome/browser/ui/views/location_bar/selected_keyword_view.h
+++ b/chrome/browser/ui/views/location_bar/selected_keyword_view.h
@@ -41,6 +41,8 @@
   void SetKeyword(const base::string16& keyword);
   const base::string16& keyword() const { return keyword_; }
 
+  using IconLabelBubbleView::label;
+
  private:
   // IconLabelBubbleView:
   const char* GetClassName() const override;
diff --git a/chrome/browser/ui/views/location_bar/selected_keyword_view_interactive_uitest.cc b/chrome/browser/ui/views/location_bar/selected_keyword_view_interactive_uitest.cc
new file mode 100644
index 0000000..55262df05
--- /dev/null
+++ b/chrome/browser/ui/views/location_bar/selected_keyword_view_interactive_uitest.cc
@@ -0,0 +1,52 @@
+// 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 "chrome/browser/ui/views/location_bar/selected_keyword_view.h"
+
+#include "chrome/browser/extensions/extension_browsertest.h"
+#include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/location_bar/location_bar_view.h"
+#include "chrome/browser/ui/views/location_bar/selected_keyword_view.h"
+#include "chrome/browser/ui/views/toolbar/toolbar_view.h"
+#include "chrome/test/base/interactive_test_utils.h"
+
+namespace {
+
+void InputKeys(Browser* browser, const std::vector<ui::KeyboardCode>& keys) {
+  for (auto key : keys) {
+    ASSERT_TRUE(ui_test_utils::SendKeyPressSync(browser, key, false, false,
+                                                false, false));
+  }
+}
+
+using SelectedKeywordViewTest = ExtensionBrowserTest;
+
+// Tests that an extension's short name is registered as the value of the
+// extension's omnibox keyword. When the extension's omnibox keyword is
+// activated, then the selected keyword label in the omnibox should be the
+// extension's short name.
+IN_PROC_BROWSER_TEST_F(SelectedKeywordViewTest,
+                       TestSelectedKeywordViewIsExtensionShortname) {
+  const extensions::Extension* extension =
+      InstallExtension(test_data_dir_.AppendASCII("omnibox"), 1);
+  ASSERT_TRUE(extension);
+
+  chrome::FocusLocationBar(browser());
+  ASSERT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
+
+  // Activate the extension's omnibox keyword.
+  InputKeys(browser(), {ui::VKEY_K, ui::VKEY_E, ui::VKEY_Y, ui::VKEY_SPACE});
+
+  BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser());
+  SelectedKeywordView* selected_keyword_view =
+      browser_view->toolbar()->location_bar()->selected_keyword_view();
+  ASSERT_TRUE(selected_keyword_view);
+
+  // Verify that the label in the omnibox is the extension's shortname.
+  EXPECT_EQ(extension->short_name(),
+            base::UTF16ToUTF8(selected_keyword_view->label()->text()));
+}
+
+}  // namespace
diff --git a/chrome/browser/ui/views/page_info/page_info_bubble_view.cc b/chrome/browser/ui/views/page_info/page_info_bubble_view.cc
index 0ab7f29..251d146 100644
--- a/chrome/browser/ui/views/page_info/page_info_bubble_view.cc
+++ b/chrome/browser/ui/views/page_info/page_info_bubble_view.cc
@@ -285,7 +285,7 @@
   layout->StartRow(0, label_column_status);
   password_reuse_button_container_ = new views::View();
   password_reuse_button_container_->SetLayoutManager(
-      new views::BoxLayout(views::BoxLayout::kHorizontal));
+      new views::BoxLayout(views::BoxLayout::kHorizontal, gfx::Insets(), 8));
   layout->AddView(password_reuse_button_container_, 1, 1,
                   views::GridLayout::FILL, views::GridLayout::LEADING);
 
diff --git a/chrome/browser/ui/webui/interstitials/interstitial_ui.cc b/chrome/browser/ui/webui/interstitials/interstitial_ui.cc
index 5ff5332f..42e285e 100644
--- a/chrome/browser/ui/webui/interstitials/interstitial_ui.cc
+++ b/chrome/browser/ui/webui/interstitials/interstitial_ui.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/safe_browsing/test_safe_browsing_blocking_page_quiet.h"
 #include "chrome/browser/safe_browsing/ui_manager.h"
 #include "chrome/browser/ssl/bad_clock_blocking_page.h"
+#include "chrome/browser/ssl/mitm_software_blocking_page.h"
 #include "chrome/browser/ssl/ssl_blocking_page.h"
 #include "chrome/browser/supervised_user/supervised_user_interstitial.h"
 #include "chrome/common/features.h"
@@ -174,6 +175,27 @@
       base::Callback<void(content::CertificateRequestResultType)>());
 }
 
+MITMSoftwareBlockingPage* CreateMITMSoftwareBlockingPage(
+    content::WebContents* web_contents) {
+  const int cert_error = net::ERR_CERT_AUTHORITY_INVALID;
+  const GURL request_url("https://example.com");
+  const std::string mitm_software_name = "Misconfigured Antivirus";
+  bool is_enterprise_managed = false;
+
+  std::string is_enterprise_managed_param;
+  if (net::GetValueForKeyInQuery(web_contents->GetURL(), "enterprise",
+                                 &is_enterprise_managed_param)) {
+    is_enterprise_managed = is_enterprise_managed_param == "1";
+  }
+
+  net::SSLInfo ssl_info;
+  ssl_info.cert = ssl_info.unverified_cert = CreateFakeCert();
+  return new MITMSoftwareBlockingPage(
+      web_contents, cert_error, request_url, nullptr, ssl_info,
+      mitm_software_name, is_enterprise_managed,
+      base::Callback<void(content::CertificateRequestResultType)>());
+}
+
 BadClockBlockingPage* CreateBadClockBlockingPage(
     content::WebContents* web_contents) {
   // Set up a fake clock error.
@@ -420,6 +442,9 @@
                               base::CompareCase::SENSITIVE)) {
     interstitial_delegate.reset(
         CreateSSLBlockingPage(web_contents, true /* is superfish */));
+  } else if (base::StartsWith(path, "mitm-software-ssl",
+                              base::CompareCase::SENSITIVE)) {
+    interstitial_delegate.reset(CreateMITMSoftwareBlockingPage(web_contents));
   } else if (base::StartsWith(path, "safebrowsing",
                               base::CompareCase::SENSITIVE)) {
     interstitial_delegate.reset(CreateSafeBrowsingBlockingPage(web_contents));
diff --git a/chrome/browser/ui/webui/interstitials/interstitial_ui_browsertest.cc b/chrome/browser/ui/webui/interstitials/interstitial_ui_browsertest.cc
index bc4f800..b6f0b60 100644
--- a/chrome/browser/ui/webui/interstitials/interstitial_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/interstitials/interstitial_ui_browsertest.cc
@@ -57,6 +57,11 @@
                    "Privacy error");
 }
 
+IN_PROC_BROWSER_TEST_F(InterstitialUITest, MITMSoftwareInterstitial) {
+  TestInterstitial(GURL("chrome://interstitials/mitm-software-ssl"),
+                   "Privacy error");
+}
+
 IN_PROC_BROWSER_TEST_F(InterstitialUITest, PinnedCertInterstitial) {
   TestInterstitial(GURL("chrome://interstitials/ssl?type=hpkp_failure"),
                    "Privacy error");
diff --git a/chrome/browser/ui/webui/md_bookmarks/md_bookmarks_ui.cc b/chrome/browser/ui/webui/md_bookmarks/md_bookmarks_ui.cc
index ef46a7c..848cd75 100644
--- a/chrome/browser/ui/webui/md_bookmarks/md_bookmarks_ui.cc
+++ b/chrome/browser/ui/webui/md_bookmarks/md_bookmarks_ui.cc
@@ -55,6 +55,8 @@
                              IDS_BOOKMARK_MANAGER_URL_INPUT_PLACE_HOLDER);
   AddLocalizedString(source, "emptyList",
                      IDS_MD_BOOKMARK_MANAGER_EMPTY_LIST);
+  AddLocalizedString(source, "folderLabel",
+                     IDS_MD_BOOKMARK_MANAGER_FOLDER_LABEL);
   AddLocalizedString(source, "itemsSelected",
                      IDS_MD_BOOKMARK_MANAGER_ITEMS_SELECTED);
   AddLocalizedString(source, "menuAddBookmark",
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 c47e8ba..eea7e54 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
@@ -1859,6 +1859,7 @@
      IDS_SETTINGS_SITE_SETTINGS_SOURCE_KILL_SWITCH},
     {"siteSettingsReset", IDS_SETTINGS_SITE_SETTINGS_RESET_BUTTON},
     {"siteSettingsCookieHeader", IDS_SETTINGS_SITE_SETTINGS_COOKIE_HEADER},
+    {"siteSettingsCookieLink", IDS_SETTINGS_SITE_SETTINGS_COOKIE_LINK},
     {"siteSettingsCookieRemove", IDS_SETTINGS_SITE_SETTINGS_COOKIE_REMOVE},
     {"siteSettingsCookieRemoveAll",
      IDS_SETTINGS_SITE_SETTINGS_COOKIE_REMOVE_ALL},
diff --git a/chrome/browser/ui/webui/welcome_handler.cc b/chrome/browser/ui/webui/welcome_handler.cc
index 2ce76d4d..db6e1a8 100644
--- a/chrome/browser/ui/webui/welcome_handler.cc
+++ b/chrome/browser/ui/webui/welcome_handler.cc
@@ -67,7 +67,7 @@
   // attempted to sign in.
   result_ = (result_ == WelcomeResult::ATTEMPTED)
                 ? WelcomeResult::ATTEMPTED_DECLINED
-                : result_ = WelcomeResult::DECLINED;
+                : WelcomeResult::DECLINED;
   GoToNewTabPage();
 }
 
diff --git a/chrome/browser/vr/ui_suppressed_element.h b/chrome/browser/vr/ui_suppressed_element.h
index 687142c..c657c0c 100644
--- a/chrome/browser/vr/ui_suppressed_element.h
+++ b/chrome/browser/vr/ui_suppressed_element.h
@@ -20,6 +20,7 @@
   kHttpAuth,
   kDownloadPermission,
   kFileAccessPermission,
+  kPasswordManager,
 
   // This must be last.
   kCount,
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index c7f949e2..516aed1 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -401,14 +401,15 @@
 #if !defined(OS_ANDROID)
 // Enables delaying the navigation of background tabs in order to improve
 // foreground tab's user experience.
-const base::Feature kStaggeredBackgroundTabOpen{
-    "StaggeredBackgroundTabOpen", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kStaggeredBackgroundTabOpening{
+    "StaggeredBackgroundTabOpening", base::FEATURE_DISABLED_BY_DEFAULT};
 
 // This controls whether we are running experiment with staggered background
-// tab open. For control group, this should be disabled. This depends on
-// |kStaggeredBackgroundTabOpen| above.
-const base::Feature kStaggeredBackgroundTabOpenExperiment{
-    "StaggeredBackgroundTabOpenExperiment", base::FEATURE_ENABLED_BY_DEFAULT};
+// tab opening feature. For control group, this should be disabled. This depends
+// on |kStaggeredBackgroundTabOpening| above.
+const base::Feature kStaggeredBackgroundTabOpeningExperiment{
+    "StaggeredBackgroundTabOpeningExperiment",
+    base::FEATURE_ENABLED_BY_DEFAULT};
 #endif
 
 // Enables or disables the creation of (legacy) supervised users. Does not
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index 1be57a3a..7612bcb9 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -208,8 +208,8 @@
 extern const base::Feature kSoundContentSetting;
 
 #if !defined(OS_ANDROID)
-extern const base::Feature kStaggeredBackgroundTabOpen;
-extern const base::Feature kStaggeredBackgroundTabOpenExperiment;
+extern const base::Feature kStaggeredBackgroundTabOpening;
+extern const base::Feature kStaggeredBackgroundTabOpeningExperiment;
 #endif
 
 extern const base::Feature kSupervisedUserCreation;
diff --git a/chrome/common/extensions/api/BUILD.gn b/chrome/common/extensions/api/BUILD.gn
index c55e859f..ad37031 100644
--- a/chrome/common/extensions/api/BUILD.gn
+++ b/chrome/common/extensions/api/BUILD.gn
@@ -177,7 +177,6 @@
     "proxy.json",
     "tts_engine.json",
     "tts.json",
-    "types_private.json",
     "webstore.json",
   ]
   if (is_chromeos) {
diff --git a/chrome/common/extensions/api/preferences_private.json b/chrome/common/extensions/api/preferences_private.json
index e409fb1..7aff5bd 100644
--- a/chrome/common/extensions/api/preferences_private.json
+++ b/chrome/common/extensions/api/preferences_private.json
@@ -6,12 +6,35 @@
   {
     "namespace": "preferencesPrivate",
     "description": "none",
+    "types": [{
+      "id": "EasyUnlockProximityRequired",
+      "type": "object",
+      "js_module": "EasyUnlockProximityRequired",
+      "events": [{
+        "name": "onChange",
+        "description": "Fired after the setting changes.",
+        "parameters": [{
+          "type": "object",
+          "name": "details",
+          "properties": {
+            "value": {
+              "description": "The value of the setting after the change.",
+              "type": "any"
+            },
+            "incognitoSpecific": {
+              "description": "Whether the value that has changed is specific to the incognito session.<br/>This property will <em>only</em> be present if the user has enabled the extension in incognito mode.",
+              "type": "boolean",
+              "optional": true
+            }
+          }
+        }]
+      }]
+    }],
     "properties": {
       "easyUnlockProximityRequired": {
         "nocompile": true,
-        "$ref": "types.private.ChromeDirectSetting",
-        "value": ["easy_unlock.proximity_required", {"type":"boolean"}],
-        "description": "If true, a remote Easy Unlock device can only unlock the local device if it is in very close proximity (roughly, within a foot). This preference's value is a boolean, defaulting to <code>false</code>."
+        "$ref": "EasyUnlockProximityRequired",
+        "value": ["easyUnlockProximityRequired"]
       }
     }
   }
diff --git a/chrome/common/extensions/api/types_private.json b/chrome/common/extensions/api/types_private.json
deleted file mode 100644
index af2f733..0000000
--- a/chrome/common/extensions/api/types_private.json
+++ /dev/null
@@ -1,146 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-[
-  {
-    "namespace": "types.private",
-    "description": "The <code>chrome.types.private</code> API contains private type declarations for Chrome.",
-    "types": [
-      {
-        "id": "Scope",
-        "type": "string",
-        "enum": ["regular", "regular_only", "incognito_persistent", "incognito_session_only"]
-      },
-      {
-        "id": "ChromeDirectSetting",
-        "type": "object",
-        "js_module": "ChromeDirectSetting",
-        "customBindings": "ChromeDirectSetting",
-        "description": "An interface that allows component extensions direct access to a Chrome browser setting.",
-        "functions": [
-          {
-            "name": "get",
-            "type": "function",
-            "description": "Gets the value of a setting.",
-            "parameters": [
-              {
-                "name": "details",
-                "type": "object",
-                "description": "Which setting to consider.",
-                "properties": {
-                  "incognito": {
-                    "type": "boolean",
-                    "optional": true,
-                    "description": "Whether to return the value that applies to the incognito session (default false)."
-                  }
-                }
-              },
-              {
-                "name": "callback",
-                "type": "function",
-                "parameters": [
-                  {
-                    "name": "details",
-                    "type": "object",
-                    "description": "Details of the currently effective value.",
-                    "properties": {
-                      "value": {
-                        "description": "The value of the setting.",
-                        "type": "any"
-                      },
-                      "incognitoSpecific": {
-                        "description": "Whether the effective value is specific to the incognito session.<br/>This property will <em>only</em> be present if the <var>incognito</var> property in the <var>details</var> parameter of <code>get()</code> was true.",
-                        "type": "boolean",
-                        "optional": true
-                      }
-                    }
-                  }
-                ]
-              }
-            ]
-          },
-          {
-            "name": "set",
-            "type": "function",
-            "description": "Sets the value of a setting.",
-            "parameters": [
-              {
-                "name": "details",
-                "type": "object",
-                "description": "Which setting to change.",
-                "properties": {
-                  "value": {
-                    "description": "The value of the setting. <br/>Note that every setting has a specific value type, which is described together with the setting. An extension should <em>not</em> set a value of a different type.",
-                    "type": "any"
-                  },
-                  "scope": {
-                    "$ref": "Scope",
-                    "optional": true,
-                    "description": "Where to set the setting (default: regular). One of<ul><li><var>regular</var>: setting for the regular profile (which is inherited by the incognito profile if not overridden elsewhere),</li><li><var>regular_only</var>: setting for the regular profile only (not inherited by the incognito profile),</li><li><var>incognito_persistent</var>: setting for the incognito profile that survives browser restarts (overrides regular preferences),</li><li><var>incognito_session_only</var>: setting for the incognito profile that can only be set during an incognito session and is deleted when the incognito session ends (overrides regular and incognito_persistent preferences).</li></ul>"
-                  }
-                }
-              },
-              {
-                "name": "callback",
-                "type": "function",
-                "description": "Called at the completion of the set operation.",
-                "optional": true,
-                "parameters": []
-              }
-            ]
-          },
-          {
-            "name": "clear",
-            "type": "function",
-            "description": "Clears the setting, restoring any default value.",
-            "parameters": [
-              {
-                "name": "details",
-                "type": "object",
-                "description": "Which setting to clear.",
-                "properties": {
-                  "scope": {
-                    "$ref": "Scope",
-                    "optional": true,
-                    "description": "Where to clear the setting (default: regular). One of<ul><li><var>regular</var>: setting for the regular profile (which is inherited by the incognito profile if not overridden elsewhere),</li><li><var>regular_only</var>: setting for the regular profile only (not inherited by the incognito profile),</li><li><var>incognito_persistent</var>: setting for the incognito profile that survives browser restarts (overrides regular preferences),</li><li><var>incognito_session_only</var>: setting for the incognito profile that can only be set during an incognito session and is deleted when the incognito session ends (overrides regular and incognito_persistent preferences).</li></ul>"
-                  }
-                }
-              },
-              {
-                "name": "callback",
-                "type": "function",
-                "description": "Called at the completion of the clear operation.",
-                "optional": true,
-                "parameters": []
-              }
-            ]
-          }
-        ],
-        "events": [
-          {
-            "name": "onChange",
-            "description": "Fired after the setting changes.",
-            "parameters": [
-              {
-                "type": "object",
-                "name": "details",
-                "properties": {
-                  "value": {
-                    "description": "The value of the setting after the change.",
-                    "type": "any"
-                  },
-                  "incognitoSpecific": {
-                    "description": "Whether the value that has changed is specific to the incognito session.<br/>This property will <em>only</em> be present if the user has enabled the extension in incognito mode.",
-                    "type": "boolean",
-                    "optional": true
-                  }
-                }
-              }
-            ]
-          }
-        ]
-      }
-    ]
-  }
-]
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 5dace04..dc35aa3f 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -1404,29 +1404,6 @@
 const char kStabilitySystemUncleanShutdownCount[] =
     "user_experience_metrics.stability.system_unclean_shutdowns";
 
-#if defined(OS_ANDROID)
-// Activity type that is currently in the foreground for the UMA session.
-// Uses the ActivityTypeIds::Type enum.
-const char kStabilityForegroundActivityType[] =
-    "user_experience_metrics.stability.current_foreground_activity_type";
-
-// Tracks which Activities were launched during the last session.
-// See |metrics_service_android.cc| for its usage.
-const char kStabilityLaunchedActivityFlags[] =
-    "user_experience_metrics.stability.launched_activity_flags";
-
-// List pref: Counts how many times each Activity was launched.
-// Indexed into by ActivityTypeIds::Type.
-const char kStabilityLaunchedActivityCounts[] =
-    "user_experience_metrics.stability.launched_activity_counts";
-
-// List pref: Counts how many times each Activity type was in the foreground
-// when a UMA session failed to be shut down properly.
-// Indexed into by ActivityTypeIds::Type.
-const char kStabilityCrashedActivityCounts[] =
-    "user_experience_metrics.stability.crashed_activity_counts";
-#endif  // defined(OS_ANDROID)
-
 // The keys below are used for the dictionaries in the
 // kStabilityPluginStats list.
 const char kStabilityPluginName[] = "name";
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index a891eca..7d3c963 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -498,12 +498,6 @@
 extern const char kStabilityOtherUserCrashCount[];
 extern const char kStabilityKernelCrashCount[];
 extern const char kStabilitySystemUncleanShutdownCount[];
-#if defined(OS_ANDROID)
-extern const char kStabilityForegroundActivityType[];
-extern const char kStabilityLaunchedActivityFlags[];
-extern const char kStabilityLaunchedActivityCounts[];
-extern const char kStabilityCrashedActivityCounts[];
-#endif  // defined(OS_ANDROID)
 
 extern const char kStabilityPluginStats[];
 extern const char kStabilityPluginName[];
diff --git a/chrome/common/profiling/memlog_allocator_shim.cc b/chrome/common/profiling/memlog_allocator_shim.cc
index 34671825..50584ce 100644
--- a/chrome/common/profiling/memlog_allocator_shim.cc
+++ b/chrome/common/profiling/memlog_allocator_shim.cc
@@ -25,12 +25,6 @@
 
 MemlogSenderPipe* g_sender_pipe = nullptr;
 
-// This maximum number of stack entries to log. Long-term we will likely want
-// to raise this to avoid truncation. This matches the current value in the
-// in-process heap profiler (heap_profiler_allocation_context.h) so the two
-// systems performance and memory overhead can be compared consistently.
-constexpr int kMaxStackEntries = 48;
-
 #if defined(OS_WIN)
 // Matches the native buffer size on the pipe.
 constexpr int kSendBufferSize = 65536;
diff --git a/chrome/common/profiling/memlog_stream.h b/chrome/common/profiling/memlog_stream.h
index aca66ce..034c9ff 100644
--- a/chrome/common/profiling/memlog_stream.h
+++ b/chrome/common/profiling/memlog_stream.h
@@ -15,6 +15,7 @@
 
 constexpr uint32_t kAllocPacketType = 0xA1A1A1A1;
 constexpr uint32_t kFreePacketType = 0xFEFEFEFE;
+constexpr uint32_t kMaxStackEntries = 256;
 
 #pragma pack(push, 1)
 struct StreamHeader {
diff --git a/chrome/gpu/chrome_content_gpu_client.cc b/chrome/gpu/chrome_content_gpu_client.cc
index a4e904fc..bcd0060 100644
--- a/chrome/gpu/chrome_content_gpu_client.cc
+++ b/chrome/gpu/chrome_content_gpu_client.cc
@@ -50,7 +50,7 @@
 
 ChromeContentGpuClient::~ChromeContentGpuClient() {}
 
-void ChromeContentGpuClient::Initialize(
+void ChromeContentGpuClient::InitializeRegistry(
     service_manager::BinderRegistry* registry) {
 #if defined(OS_CHROMEOS)
   registry->AddInterface(
diff --git a/chrome/gpu/chrome_content_gpu_client.h b/chrome/gpu/chrome_content_gpu_client.h
index 45b056d..78abc0e 100644
--- a/chrome/gpu/chrome_content_gpu_client.h
+++ b/chrome/gpu/chrome_content_gpu_client.h
@@ -24,7 +24,7 @@
   ~ChromeContentGpuClient() override;
 
   // content::ContentGpuClient:
-  void Initialize(service_manager::BinderRegistry* registry) override;
+  void InitializeRegistry(service_manager::BinderRegistry* registry) override;
   void GpuServiceInitialized(
       const gpu::GpuPreferences& gpu_preferences) override;
 
diff --git a/chrome/installer/util/shell_util.cc b/chrome/installer/util/shell_util.cc
index 73c5ce4..fd5749f 100644
--- a/chrome/installer/util/shell_util.cc
+++ b/chrome/installer/util/shell_util.cc
@@ -866,16 +866,16 @@
   return false;
 }
 
-// Returns the installation suffix for |mode| at the current install level
-// (system or user).
-base::string16 GetInstallationSuffixForMode(
-    const install_static::InstallConstants& mode) {
+// Returns the installation suffix for |mode| at the system or user level based
+// on |system_install|.
+base::string16 GetInstallationSuffixForModeAtLevel(
+    const install_static::InstallConstants& mode,
+    bool system_install) {
   // Search based on the default install location for the mode. If we ever
   // support customizing the install location (https://crbug.com/113987,
   // https://crbug.com/302491) this will have to change to something else, such
   // as probing the Omaha keys in the registry to see where the mode is
   // installed.
-  const bool system_install = !InstallUtil::IsPerUserInstall();
   const base::FilePath chrome_exe =
       installer::GetChromeInstallPath(system_install)
           .Append(installer::kChromeExe);
@@ -900,14 +900,15 @@
   return tested_suffix;
 }
 
-// Returns |mode|'s application name. This application name will be suffixed as
-// is appropriate for the install. This is the name that is registered with
-// Default Programs on Windows and that should thus be used to "make chrome
-// default" and such.
-base::string16 GetApplicationNameForMode(
-    const install_static::InstallConstants& mode) {
+// Returns |mode|'s application name at the system or user level based on
+// |system_install|. This application name will be suffixed as is appropriate
+// for the install. This is the name that is registered with Default Programs on
+// Windows and that should thus be used to "make chrome default" and such.
+base::string16 GetApplicationNameForModeAtLevel(
+    const install_static::InstallConstants& mode,
+    bool system_install) {
   return base::string16(mode.base_app_name)
-      .append(GetInstallationSuffixForMode(mode));
+      .append(GetInstallationSuffixForModeAtLevel(mode, system_install));
 }
 
 // Returns true if the current install's |chrome_exe| has been registered with
@@ -1186,16 +1187,19 @@
 
   base::string16 app_name(GetApplicationName(chrome_exe));
 
-  // Generate the app names for this brand's other install modes.
+  // Generate the app names for this brand's other install modes at both user
+  // and system levels.
   const int current_install_mode_index =
       install_static::InstallDetails::Get().install_mode_index();
-  base::string16 other_app_names[install_static::NUM_INSTALL_MODES];
+  base::string16 other_app_names[install_static::NUM_INSTALL_MODES * 2];
   for (int mode_index = 0; mode_index < install_static::NUM_INSTALL_MODES;
        ++mode_index) {
     if (mode_index == current_install_mode_index)
       continue;  // Leave the entry for the current mode empty.
-    other_app_names[mode_index] =
-        GetApplicationNameForMode(install_static::kInstallModes[mode_index]);
+    other_app_names[mode_index * 2] = GetApplicationNameForModeAtLevel(
+        install_static::kInstallModes[mode_index], false);
+    other_app_names[mode_index * 2 + 1] = GetApplicationNameForModeAtLevel(
+        install_static::kInstallModes[mode_index], true);
   }
 
   // Now check each protocol to see if this brand is default for all. This loop
@@ -1204,12 +1208,11 @@
   for (size_t i = 0; i < num_protocols; ++i) {
     const wchar_t* protocol = protocols[i];
     BOOL result = TRUE;
-    // Check the current app name.
+    // Check the current app name. This will fail (e.g., ERROR_FILE_NOT_FOUND)
+    // if |app_name| isn't registered.
     hr = registration->QueryAppIsDefault(protocol, AT_URLPROTOCOL, AL_EFFECTIVE,
                                          app_name.c_str(), &result);
-    if (FAILED(hr))
-      return ShellUtil::NOT_DEFAULT;
-    if (result)
+    if (SUCCEEDED(hr) && result)
       continue;
 
     // Search for a different install mode that is the default handler.
diff --git a/chrome/profiling/json_exporter.cc b/chrome/profiling/json_exporter.cc
index 0c4bb9e..b9dde7cb 100644
--- a/chrome/profiling/json_exporter.cc
+++ b/chrome/profiling/json_exporter.cc
@@ -73,6 +73,8 @@
   out << "{ \"pid\":" << pid << ",";
   out << "\"ph\":\"v\",";
   out << "\"name\":\"periodic_interval\",";
+  out << "\"ts\": 1,";
+  out << "\"id\": \"1\",";
   out << "\"args\":{";
   out << "\"dumps\":";
 }
diff --git a/chrome/profiling/json_exporter_unittest.cc b/chrome/profiling/json_exporter_unittest.cc
index 0b66ee0..3163ab70 100644
--- a/chrome/profiling/json_exporter_unittest.cc
+++ b/chrome/profiling/json_exporter_unittest.cc
@@ -137,6 +137,47 @@
 
 }  // namespace
 
+TEST(ProfilingJsonExporterTest, DumpsHeader) {
+  BacktraceStorage backtrace_storage;
+  AllocationEventSet events;
+  std::ostringstream stream;
+  ExportAllocationEventSetToJSON(1234, events, MemoryMap(), stream, nullptr,
+                                 kNoSizeThreshold, kNoCountThreshold);
+  std::string json = stream.str();
+
+  // JSON should parse.
+  base::JSONReader reader(base::JSON_PARSE_RFC);
+  std::unique_ptr<base::Value> root = reader.ReadToValue(stream.str());
+  ASSERT_EQ(base::JSONReader::JSON_NO_ERROR, reader.error_code())
+      << reader.GetErrorMessage();
+  ASSERT_TRUE(root);
+
+  // Find the periodic_interval event.
+  const base::Value* periodic_interval = FindFirstPeriodicInterval(*root);
+  ASSERT_TRUE(periodic_interval) << "Array contains no periodic_interval";
+
+  // The following fields are mandatory to make a trace viewable in
+  // chrome://tracing UI.
+  const base::Value* pid =
+      periodic_interval->FindKeyOfType("pid", base::Value::Type::INTEGER);
+  ASSERT_TRUE(pid);
+  EXPECT_NE(0, pid->GetInt());
+
+  const base::Value* ts =
+      periodic_interval->FindKeyOfType("ts", base::Value::Type::INTEGER);
+  ASSERT_TRUE(ts);
+  EXPECT_NE(0, ts->GetInt());
+
+  const base::Value* id =
+      periodic_interval->FindKeyOfType("id", base::Value::Type::STRING);
+  ASSERT_TRUE(id);
+  EXPECT_NE("", id->GetString());
+
+  const base::Value* args =
+      periodic_interval->FindKeyOfType("args", base::Value::Type::DICTIONARY);
+  ASSERT_TRUE(args);
+}
+
 TEST(ProfilingJsonExporterTest, Simple) {
   BacktraceStorage backtrace_storage;
 
diff --git a/chrome/profiling/memlog_stream_parser.cc b/chrome/profiling/memlog_stream_parser.cc
index 5fb23cf..6186444 100644
--- a/chrome/profiling/memlog_stream_parser.cc
+++ b/chrome/profiling/memlog_stream_parser.cc
@@ -16,11 +16,7 @@
 
 namespace {
 
-// Maximum number of items we'll parse from a stack before declaring the
-// message is corrupt.
-constexpr size_t kMaxStackCount = 128;
-
-using AddressVector = base::StackVector<Address, kMaxStackCount>;
+using AddressVector = base::StackVector<Address, kMaxStackEntries>;
 
 }  // namespace
 
@@ -164,7 +160,7 @@
     return READ_NO_DATA;
 
   std::vector<Address> stack;
-  if (alloc_packet.stack_len > kMaxStackCount)
+  if (alloc_packet.stack_len > kMaxStackEntries)
     return READ_ERROR;  // Prevent overflow on corrupted or malicious data.
   stack.resize(alloc_packet.stack_len);
   size_t stack_byte_size = sizeof(Address) * alloc_packet.stack_len;
diff --git a/chrome/renderer/BUILD.gn b/chrome/renderer/BUILD.gn
index 3c32bce4..82318fb 100644
--- a/chrome/renderer/BUILD.gn
+++ b/chrome/renderer/BUILD.gn
@@ -72,8 +72,6 @@
     "page_load_metrics/page_timing_metrics_sender.cc",
     "page_load_metrics/page_timing_metrics_sender.h",
     "page_load_metrics/page_timing_sender.h",
-    "page_load_metrics/renderer_page_track_decider.cc",
-    "page_load_metrics/renderer_page_track_decider.h",
     "plugins/non_loadable_plugin_placeholder.cc",
     "plugins/non_loadable_plugin_placeholder.h",
     "plugins/pdf_plugin_placeholder.cc",
@@ -301,10 +299,10 @@
       "resources/extensions/app_custom_bindings.js",
       "resources/extensions/automation_custom_bindings.js",
       "resources/extensions/browser_action_custom_bindings.js",
-      "resources/extensions/chrome_direct_setting.js",
       "resources/extensions/chrome_setting.js",
       "resources/extensions/content_setting.js",
       "resources/extensions/declarative_content_custom_bindings.js",
+      "resources/extensions/easy_unlock_proximity_required.js",
       "resources/extensions/enterprise_platform_keys_custom_bindings.js",
       "resources/extensions/feedback_private_custom_bindings.js",
       "resources/extensions/gcm_custom_bindings.js",
diff --git a/chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc b/chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc
index 8676962..1180519d 100644
--- a/chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc
+++ b/chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc
@@ -289,8 +289,8 @@
     // Custom types sources.
     source_map->RegisterSource("ChromeSetting", IDR_CHROME_SETTING_JS);
     source_map->RegisterSource("ContentSetting", IDR_CONTENT_SETTING_JS);
-    source_map->RegisterSource("ChromeDirectSetting",
-                               IDR_CHROME_DIRECT_SETTING_JS);
+    source_map->RegisterSource("EasyUnlockProximityRequired",
+                               IDR_EASY_UNLOCK_PROXIMITY_REQUIRED_JS);
   }
 }
 
diff --git a/chrome/renderer/page_load_metrics/metrics_render_frame_observer.cc b/chrome/renderer/page_load_metrics/metrics_render_frame_observer.cc
index 99ad6df..c545e4fa 100644
--- a/chrome/renderer/page_load_metrics/metrics_render_frame_observer.cc
+++ b/chrome/renderer/page_load_metrics/metrics_render_frame_observer.cc
@@ -12,7 +12,6 @@
 #include "base/timer/timer.h"
 #include "chrome/renderer/page_load_metrics/page_timing_metrics_sender.h"
 #include "chrome/renderer/page_load_metrics/page_timing_sender.h"
-#include "chrome/renderer/page_load_metrics/renderer_page_track_decider.h"
 #include "chrome/renderer/searchbox/search_bouncer.h"
 #include "content/public/common/associated_interface_provider.h"
 #include "content/public/renderer/render_frame.h"
@@ -96,14 +95,11 @@
   // Make sure to release the sender for a previous navigation, if we have one.
   page_timing_metrics_sender_.reset();
 
-  // We only create a PageTimingMetricsSender if the page meets the criteria for
-  // sending and recording metrics. Once page_timing_metrics_sender_ is
-  // non-null, we will send metrics for the current page at some later time, as
-  // those metrics become available.
-  if (ShouldSendMetrics()) {
-    page_timing_metrics_sender_ = base::MakeUnique<PageTimingMetricsSender>(
-        CreatePageTimingSender(), CreateTimer(), GetTiming());
-  }
+  if (HasNoRenderFrame())
+    return;
+
+  page_timing_metrics_sender_ = base::MakeUnique<PageTimingMetricsSender>(
+      CreatePageTimingSender(), CreateTimer(), GetTiming());
 }
 
 void MetricsRenderFrameObserver::SendMetrics() {
@@ -114,15 +110,6 @@
   page_timing_metrics_sender_->Send(GetTiming());
 }
 
-bool MetricsRenderFrameObserver::ShouldSendMetrics() const {
-  if (HasNoRenderFrame())
-    return false;
-  const blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
-  const blink::WebDocument& document = frame->GetDocument();
-  return RendererPageTrackDecider(&document, frame->GetDocumentLoader())
-      .ShouldTrack();
-}
-
 mojom::PageLoadTimingPtr MetricsRenderFrameObserver::GetTiming() const {
   const blink::WebPerformance& perf =
       render_frame()->GetWebFrame()->Performance();
diff --git a/chrome/renderer/page_load_metrics/metrics_render_frame_observer.h b/chrome/renderer/page_load_metrics/metrics_render_frame_observer.h
index bc66beb..7eefbb5 100644
--- a/chrome/renderer/page_load_metrics/metrics_render_frame_observer.h
+++ b/chrome/renderer/page_load_metrics/metrics_render_frame_observer.h
@@ -46,7 +46,6 @@
 
  private:
   void SendMetrics();
-  virtual bool ShouldSendMetrics() const;
   virtual mojom::PageLoadTimingPtr GetTiming() const;
   virtual std::unique_ptr<base::Timer> CreateTimer();
   virtual std::unique_ptr<PageTimingSender> CreatePageTimingSender();
diff --git a/chrome/renderer/page_load_metrics/metrics_render_frame_observer_unittest.cc b/chrome/renderer/page_load_metrics/metrics_render_frame_observer_unittest.cc
index 8dbb975..30745f6 100644
--- a/chrome/renderer/page_load_metrics/metrics_render_frame_observer_unittest.cc
+++ b/chrome/renderer/page_load_metrics/metrics_render_frame_observer_unittest.cc
@@ -17,9 +17,9 @@
 
 namespace page_load_metrics {
 
-// Implementation of the MetricsRenderFrameObserver class we're testing,
-// with the GetTiming() and ShouldSendMetrics() methods stubbed out to make
-// the rest of the class more testable.
+// Implementation of the MetricsRenderFrameObserver class we're testing, with
+// the GetTiming() method stubbed out to make the rest of the class more
+// testable.
 class TestMetricsRenderFrameObserver : public MetricsRenderFrameObserver,
                                        public test::WeakMockTimerProvider {
  public:
@@ -56,7 +56,6 @@
     validator_.VerifyExpectedTimings();
   }
 
-  bool ShouldSendMetrics() const override { return true; }
   bool HasNoRenderFrame() const override { return false; }
 
  private:
diff --git a/chrome/renderer/page_load_metrics/renderer_page_track_decider.cc b/chrome/renderer/page_load_metrics/renderer_page_track_decider.cc
deleted file mode 100644
index 1969576..0000000
--- a/chrome/renderer/page_load_metrics/renderer_page_track_decider.cc
+++ /dev/null
@@ -1,58 +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.
-
-#include "chrome/renderer/page_load_metrics/renderer_page_track_decider.h"
-
-#include <string>
-
-#include "chrome/renderer/searchbox/search_bouncer.h"
-#include "third_party/WebKit/public/platform/WebURLResponse.h"
-#include "third_party/WebKit/public/web/WebDocument.h"
-#include "third_party/WebKit/public/web/WebDocumentLoader.h"
-#include "url/gurl.h"
-
-namespace page_load_metrics {
-
-RendererPageTrackDecider::RendererPageTrackDecider(
-    const blink::WebDocument* document,
-    const blink::WebDocumentLoader* document_loader)
-    : document_(document), document_loader_(document_loader) {}
-
-RendererPageTrackDecider::~RendererPageTrackDecider() {}
-
-bool RendererPageTrackDecider::HasCommitted() {
-  // RendererPageTrackDecider is only instantiated for committed pages.
-  return true;
-}
-
-bool RendererPageTrackDecider::IsHttpOrHttpsUrl() {
-  return static_cast<GURL>(document_->Url()).SchemeIsHTTPOrHTTPS();
-}
-
-bool RendererPageTrackDecider::IsNewTabPageUrl() {
-  return SearchBouncer::GetInstance()->IsNewTabPage(document_->Url());
-}
-
-bool RendererPageTrackDecider::IsChromeErrorPage() {
-  return document_loader_->HasUnreachableURL();
-}
-
-int RendererPageTrackDecider::GetHttpStatusCode() {
-  return document_loader_->GetResponse().HttpStatusCode();
-}
-
-bool RendererPageTrackDecider::IsHtmlOrXhtmlPage() {
-  // Ignore non-HTML documents (e.g. SVG). Note that images are treated by
-  // Blink as HTML documents, so to exclude images, we must perform
-  // additional mime type checking below. MHTML is tracked as HTML in blink.
-  if (!document_->IsHTMLDocument() && !document_->IsXHTMLDocument())
-    return false;
-
-  // Ignore non-HTML mime types (e.g. images).
-  blink::WebString mime_type = document_loader_->GetResponse().MimeType();
-  return mime_type == "text/html" || mime_type == "application/xhtml+xml" ||
-         mime_type == "multipart/related";
-}
-
-}  // namespace page_load_metrics
diff --git a/chrome/renderer/page_load_metrics/renderer_page_track_decider.h b/chrome/renderer/page_load_metrics/renderer_page_track_decider.h
deleted file mode 100644
index bee5424..0000000
--- a/chrome/renderer/page_load_metrics/renderer_page_track_decider.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_RENDERER_PAGE_LOAD_METRICS_RENDERER_PAGE_TRACK_DECIDER_H_
-#define CHROME_RENDERER_PAGE_LOAD_METRICS_RENDERER_PAGE_TRACK_DECIDER_H_
-
-#include "base/macros.h"
-#include "chrome/common/page_load_metrics/page_track_decider.h"
-
-namespace blink {
-class WebDocument;
-class WebDocumentLoader;
-}  // namespace blink
-
-namespace page_load_metrics {
-
-class RendererPageTrackDecider : public PageTrackDecider {
- public:
-  // document and document_loader are not owned by RendererPageTrackDecider,
-  // and must outlive the RendererPageTrackDecider.
-  RendererPageTrackDecider(const blink::WebDocument* document,
-                           const blink::WebDocumentLoader* document_loader);
-  ~RendererPageTrackDecider() override;
-
-  bool HasCommitted() override;
-  bool IsHttpOrHttpsUrl() override;
-  bool IsNewTabPageUrl() override;
-  bool IsChromeErrorPage() override;
-  bool IsHtmlOrXhtmlPage() override;
-  int GetHttpStatusCode() override;
-
- private:
-  const blink::WebDocument* const document_;
-  const blink::WebDocumentLoader* const document_loader_;
-
-  DISALLOW_COPY_AND_ASSIGN(RendererPageTrackDecider);
-};
-
-}  // namespace page_load_metrics
-
-#endif  // CHROME_RENDERER_PAGE_LOAD_METRICS_RENDERER_PAGE_TRACK_DECIDER_H_
diff --git a/chrome/renderer/resources/extensions/easy_unlock_proximity_required.js b/chrome/renderer/resources/extensions/easy_unlock_proximity_required.js
new file mode 100644
index 0000000..4f75ca1b
--- /dev/null
+++ b/chrome/renderer/resources/extensions/easy_unlock_proximity_required.js
@@ -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.
+
+var Event = require('event_bindings').Event;
+
+// The EasyUnlockProximityRequired object is just a stub that has an onChange
+// event, which is never triggered.
+// TODO(devlin): Remove this once the preferencesPrivate API is fully removed.
+// https://crbug.com/593166
+function EasyUnlockProximityRequired(prefKey, valueSchema, schema) {
+  // Note: technically, extensions could intercept this through a setter on
+  // Object.prototype(). We don't really care, because a) this is only for a
+  // private API, so we shouldn't have to worry about untrusted code, and b)
+  // this is an anonymous event, which exposes no attack surface and will be
+  // exposed to the extension anyway.
+  this.onChange = new Event();
+};
+
+exports.$set('EasyUnlockProximityRequired', EasyUnlockProximityRequired);
diff --git a/chrome/renderer/resources/renderer_resources.grd b/chrome/renderer/resources/renderer_resources.grd
index 6e937a3d..42a35a8 100644
--- a/chrome/renderer/resources/renderer_resources.grd
+++ b/chrome/renderer/resources/renderer_resources.grd
@@ -37,8 +37,6 @@
         <include name="IDR_CAST_STREAMING_SESSION_CUSTOM_BINDINGS_JS" file="extensions\cast_streaming_session_custom_bindings.js" type="BINDATA" />
         <include name="IDR_CAST_STREAMING_UDP_TRANSPORT_CUSTOM_BINDINGS_JS" file="extensions\cast_streaming_udp_transport_custom_bindings.js" type="BINDATA" />
         <include name="IDR_CAST_STREAMING_RECEIVER_SESSION_CUSTOM_BINDINGS_JS" file="extensions\cast_streaming_receiver_session_custom_bindings.js" type="BINDATA" />
-        <include name="IDR_CHROME_DIRECT_SETTING_JS"
-        file="extensions\chrome_direct_setting.js" type="BINDATA" />
         <include name="IDR_CHROME_SETTING_JS" file="extensions\chrome_setting.js" type="BINDATA" />
         <include name="IDR_CHROME_WEB_VIEW_INTERNAL_CUSTOM_BINDINGS_JS" file="extensions\web_view\chrome_web_view_internal_custom_bindings.js" type="BINDATA" />
         <include name="IDR_CHROME_WEB_VIEW_JS" file="extensions\web_view\chrome_web_view.js" type="BINDATA" />
@@ -47,6 +45,7 @@
         <include name="IDR_DESKTOP_CAPTURE_CUSTOM_BINDINGS_JS" file="extensions\desktop_capture_custom_bindings.js" type="BINDATA" />
         <include name="IDR_DEVELOPER_PRIVATE_CUSTOM_BINDINGS_JS" file="extensions\developer_private_custom_bindings.js" type="BINDATA" />
         <include name="IDR_DOWNLOADS_CUSTOM_BINDINGS_JS" file="extensions\downloads_custom_bindings.js" type="BINDATA" />
+        <include name="IDR_EASY_UNLOCK_PROXIMITY_REQUIRED_JS" file="extensions\easy_unlock_proximity_required.js" type="BINDATA" />
         <include name="IDR_FEEDBACK_PRIVATE_CUSTOM_BINDINGS_JS" file="extensions\feedback_private_custom_bindings.js" type="BINDATA" />
         <include name="IDR_GCM_CUSTOM_BINDINGS_JS" file="extensions\gcm_custom_bindings.js" type="BINDATA" />
         <include name="IDR_IDENTITY_CUSTOM_BINDINGS_JS" file="extensions\identity_custom_bindings.js" type="BINDATA" />
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index e59baff9..1426f57 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -632,6 +632,7 @@
           "../browser/ui/views/fullscreen_control/fullscreen_control_view_interactive_uitest.cc",
           "../browser/ui/views/keyboard_access_browsertest.cc",
           "../browser/ui/views/location_bar/location_icon_view_interactive_uitest.cc",
+          "../browser/ui/views/location_bar/selected_keyword_view_interactive_uitest.cc",
           "../browser/ui/views/location_bar/star_view_browsertest.cc",
           "../browser/ui/views/omnibox/omnibox_view_views_browsertest.cc",
           "../browser/ui/views/passwords/manage_passwords_icon_view_interactive_uitest.cc",
@@ -1604,8 +1605,8 @@
       "base/chrome_render_view_test.cc",
       "base/chrome_render_view_test.h",
       "base/in_process_browser_test_browsertest.cc",
+      "base/memory_tracing_browsertest.cc",
       "base/test_chrome_web_ui_controller_factory_browsertest.cc",
-      "base/tracing_browsertest.cc",
       "base/web_ui_browser_test_browsertest.cc",
       "data/webui/async_gen.cc",
       "data/webui/async_gen.h",
@@ -1877,6 +1878,7 @@
         "../browser/extensions/api/permissions/permissions_apitest.cc",
         "../browser/extensions/api/platform_keys/platform_keys_apitest_nss.cc",
         "../browser/extensions/api/preference/preference_apitest.cc",
+        "../browser/extensions/api/preference/preferences_private_apitest.cc",
         "../browser/extensions/api/processes/processes_apitest.cc",
         "../browser/extensions/api/proxy/proxy_apitest.cc",
         "../browser/extensions/api/resources_private/resources_private_apitest.cc",
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeInstrumentationTestRunner.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeInstrumentationTestRunner.java
index 5765f25a..bb70e72 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeInstrumentationTestRunner.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeInstrumentationTestRunner.java
@@ -22,6 +22,8 @@
 import org.chromium.chrome.test.util.ChromeRestriction;
 import org.chromium.content.browser.test.ChildProcessAllocatorSettingsHook;
 import org.chromium.policy.test.annotations.Policies;
+import org.chromium.ui.test.util.UiDisableIfSkipCheck;
+import org.chromium.ui.test.util.UiRestrictionSkipCheck;
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
@@ -44,6 +46,8 @@
     protected void addTestHooks(BaseTestResult result) {
         super.addTestHooks(result);
         result.addSkipCheck(new ChromeRestrictionSkipCheck(getTargetContext()));
+        result.addSkipCheck(new UiDisableIfSkipCheck(getTargetContext()));
+        result.addSkipCheck(new UiRestrictionSkipCheck(getTargetContext()));
 
         result.addPreTestHook(Policies.getRegistrationHook());
         result.addPreTestHook(new ChildProcessAllocatorSettingsHook());
diff --git a/chrome/test/base/tracing_browsertest.cc b/chrome/test/base/memory_tracing_browsertest.cc
similarity index 72%
rename from chrome/test/base/tracing_browsertest.cc
rename to chrome/test/base/memory_tracing_browsertest.cc
index d343a851..1e6f550 100644
--- a/chrome/test/base/tracing_browsertest.cc
+++ b/chrome/test/base/memory_tracing_browsertest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 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.
 
@@ -34,7 +34,7 @@
                                bool success,
                                uint64_t) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, quit_closure);
-  ASSERT_TRUE(success);
+  // TODO(ssid): Check for dump success once crbug.com/709524 is fixed.
 }
 
 void OnStartTracingDoneCallback(
@@ -46,14 +46,21 @@
           Bind(&RequestGlobalDumpCallback, quit_closure));
 }
 
-class TracingBrowserTest : public InProcessBrowserTest {
+class MemoryTracingBrowserTest : public InProcessBrowserTest {
  protected:
+  void SetUp() override {
+    should_test_memory_dump_success_ = false;
+    InProcessBrowserTest::SetUp();
+  }
+
   // Execute some no-op javascript on the current tab - this triggers a trace
   // event in RenderFrameImpl::OnJavaScriptExecuteRequestForTests (from the
   // renderer process).
   void ExecuteJavascriptOnCurrentTab() {
-    content::RenderViewHost* rvh = browser()->tab_strip_model()->
-        GetActiveWebContents()->GetRenderViewHost();
+    content::RenderViewHost* rvh = browser()
+                                       ->tab_strip_model()
+                                       ->GetActiveWebContents()
+                                       ->GetRenderViewHost();
     ASSERT_TRUE(rvh);
     ASSERT_TRUE(content::ExecuteScript(rvh, ";"));
   }
@@ -94,15 +101,22 @@
     std::string json_events;
     ASSERT_TRUE(EndTracing(&json_events));
 
-    // Expect the basic memory dumps to be present in the trace.
-    EXPECT_NE(std::string::npos, json_events.find("process_totals"));
-    EXPECT_NE(std::string::npos, json_events.find("v8"));
-    EXPECT_NE(std::string::npos, json_events.find("blink_gc"));
+    if (should_test_memory_dump_success_) {
+      // Expect the basic memory dumps to be present in the trace.
+      EXPECT_NE(std::string::npos, json_events.find("process_totals"));
+      EXPECT_NE(std::string::npos, json_events.find("v8"));
+      EXPECT_NE(std::string::npos, json_events.find("blink_gc"));
+    }
   }
+
+  bool should_test_memory_dump_success_;
 };
 
-// crbug.com/708487
-IN_PROC_BROWSER_TEST_F(TracingBrowserTest, DISABLED_TestMemoryInfra) {
+IN_PROC_BROWSER_TEST_F(MemoryTracingBrowserTest, TestMemoryInfra) {
+  // TODO(ssid): Test for dump success once the on start tracing done callback
+  // is fixed to be called after enable tracing is acked by all processes,
+  // crbug.com/709524. The test still tests if dumping does not crash.
+  should_test_memory_dump_success_ = false;
   PerformDumpMemoryTestActions(
       base::trace_event::TraceConfig(
           base::trace_event::TraceConfigMemoryTestUtil::
@@ -110,8 +124,11 @@
       base::trace_event::MemoryDumpLevelOfDetail::DETAILED);
 }
 
-// crbug.com/708487
-IN_PROC_BROWSER_TEST_F(TracingBrowserTest, DISABLED_TestBackgroundMemoryInfra) {
+IN_PROC_BROWSER_TEST_F(MemoryTracingBrowserTest, TestBackgroundMemoryInfra) {
+  // TODO(ssid): Test for dump success once the on start tracing done callback
+  // is fixed to be called after enable tracing is acked by all processes,
+  // crbug.com/709524. The test still tests if dumping does not crash.
+  should_test_memory_dump_success_ = false;
   PerformDumpMemoryTestActions(
       base::trace_event::TraceConfig(
           base::trace_event::TraceConfigMemoryTestUtil::
diff --git a/chrome/test/chromedriver/test/test_expectations b/chrome/test/chromedriver/test/test_expectations
index 743873b..13d87cd 100644
--- a/chrome/test/chromedriver/test/test_expectations
+++ b/chrome/test/chromedriver/test/test_expectations
@@ -255,6 +255,8 @@
     _OS_NEGATIVE_FILTER['android:chrome'] + [
          # https://bugs.chromium.org/p/chromedriver/issues/detail?id=998
         'ImplicitWaitTest.testShouldImplicitlyWaitForASingleElement',
+         # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1960
+        'CorrectEventFiringTest.testShouldFireMouseDownEventWhenClicking',
     ]
 )
 
diff --git a/chrome/test/data/android/webvr_instrumentation/html/webvr_page_submits_once.html b/chrome/test/data/android/webvr_instrumentation/html/webvr_page_submits_once.html
new file mode 100644
index 0000000..8047a1c
--- /dev/null
+++ b/chrome/test/data/android/webvr_instrumentation/html/webvr_page_submits_once.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<!--
+WebVR page without any code specific to one test
+-->
+<html>
+  <head>
+    <link rel="stylesheet" type="text/css" href="../resources/webvr_e2e.css">
+  </head>
+  <body>
+    <canvas id="webgl-canvas"></canvas>
+    <script src="../resources/webvr_e2e.js"></script>
+    <script src="../resources/webvr_boilerplate.js"></script>
+    <script>
+      var has_submitted = false;
+      onAnimationFrameCallback = function() {
+        if (vrDisplay.isPresenting) {
+          if (has_submitted) {
+            shouldSubmitFrame = false;
+            finishJavaScriptStep();
+          }
+          has_submitted = true;
+        }
+      };
+    </script>
+  </body>
+</html>
diff --git a/chrome/test/data/android/webvr_instrumentation/resources/webvr_boilerplate.js b/chrome/test/data/android/webvr_instrumentation/resources/webvr_boilerplate.js
index f4f4e84d..9708fac1 100644
--- a/chrome/test/data/android/webvr_instrumentation/resources/webvr_boilerplate.js
+++ b/chrome/test/data/android/webvr_instrumentation/resources/webvr_boilerplate.js
@@ -19,6 +19,7 @@
 var vrDisplay = null;
 var frameData = null;
 var onAnimationFrameCallback = null;
+var shouldSubmitFrame = true;
 
 function onResize() {
   if (vrDisplay && vrDisplay.isPresenting) {
@@ -60,7 +61,7 @@
     gl.viewport(webglCanvas.width * 0.5, 0, webglCanvas.width * 0.5,
                 webglCanvas.height);
 
-    vrDisplay.submitFrame();
+    if (shouldSubmitFrame) vrDisplay.submitFrame();
   } else {
     gl.clearColor(1.0, 0.0, 0.0, 1.0);
     gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
diff --git a/chrome/test/data/extensions/api_test/preferences_private/manifest.json b/chrome/test/data/extensions/api_test/preferences_private/manifest.json
new file mode 100644
index 0000000..68edf13
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/preferences_private/manifest.json
@@ -0,0 +1,11 @@
+{
+  "name": "preferences private test",
+  "description": "foo",
+  "manifest_version": 2,
+  "version": "0.1",
+  "permissions": ["preferencesPrivate"],
+  "background": {
+    "scripts": ["test.js"]
+  },
+  "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCXAxIB5iu+XGtMYYJgSwMrqO+zNa3FlWeMJLOV+U1T2VL6wDU3WD9YNlioI6a6wG49AFquEbRxQwwxlvAZC1c95LBvRlnQAkEVum0KbrJ8WHTxxDEPOfITE0J1AP5j8V0WQ9jbYvUxgefIPhDPXHpdPRAxDotygTrPa33x1075wIDAQAB"
+}
diff --git a/chrome/test/data/extensions/api_test/preferences_private/test.js b/chrome/test/data/extensions/api_test/preferences_private/test.js
new file mode 100644
index 0000000..f745f3c
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/preferences_private/test.js
@@ -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.
+
+chrome.test.runTests([
+  function testOnChangedExists() {
+    // Verify that the
+    // chrome.preferencesPrivate.easyUnlockProximityRequired.onChange event
+    // exists. It doesn't need to do anything other than support adding/removing
+    // listeners for backwards compatibility.
+    chrome.test.assertTrue(!!chrome.preferencesPrivate);
+    chrome.test.assertTrue(
+        !!chrome.preferencesPrivate.easyUnlockProximityRequired);
+    var onChange =
+        chrome.preferencesPrivate.easyUnlockProximityRequired.onChange;
+    chrome.test.assertTrue(!!onChange);
+    chrome.test.assertEq('function', typeof onChange.addListener);
+    chrome.test.assertEq('function', typeof onChange.removeListener);
+    chrome.test.succeed();
+  },
+]);
diff --git a/chrome/test/data/extensions/omnibox/background.js b/chrome/test/data/extensions/omnibox/background.js
new file mode 100644
index 0000000..19151af
--- /dev/null
+++ b/chrome/test/data/extensions/omnibox/background.js
@@ -0,0 +1,6 @@
+// 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.
+
+chrome.omnibox.onInputEntered.addListener(
+  function(text) {});
diff --git a/chrome/test/data/extensions/omnibox/manifest.json b/chrome/test/data/extensions/omnibox/manifest.json
new file mode 100644
index 0000000..8faae69
--- /dev/null
+++ b/chrome/test/data/extensions/omnibox/manifest.json
@@ -0,0 +1,12 @@
+{
+  "name": "Extension omnibox keyword and short name test ",
+  "short_name": "short name",
+  "version": "0.1",
+  "manifest_version": 2,
+  "description": "Tests that when the omnibox keyword is triggered, the location icon view text is the extension's short name.",
+  "background": {
+    "scripts": ["background.js"]
+  },
+  "omnibox": { "keyword": "key" }
+}
+
diff --git a/chrome/test/data/page_load_metrics/dynamic_iframe.html b/chrome/test/data/page_load_metrics/dynamic_iframe.html
new file mode 100644
index 0000000..210aab5
--- /dev/null
+++ b/chrome/test/data/page_load_metrics/dynamic_iframe.html
@@ -0,0 +1,14 @@
+<html>
+  <link rel="stylesheet" href="seamless-iframe.css">
+  <body>
+    <script>
+      var iframe = document.createElement('iframe');
+      iframe.className = 'seamless';
+      document.body.appendChild(iframe);
+      var doc = iframe.contentDocument;
+      doc.open();
+      doc.write('<html><body>Hello, world!</body></html>');
+      doc.close();
+    </script>
+  </body>
+</html>
diff --git a/chrome/test/data/webui/extensions/extension_manager_test.js b/chrome/test/data/webui/extensions/extension_manager_test.js
index d9f2a30..d07bbcc 100644
--- a/chrome/test/data/webui/extensions/extension_manager_test.js
+++ b/chrome/test/data/webui/extensions/extension_manager_test.js
@@ -117,28 +117,31 @@
 
       // Toggle between extensions and apps and back again.
       expectEquals(manager.extensions, manager.$['items-list'].items);
-      manager.listHelper_.showType(extensions.ShowingType.APPS);
+      extensions.navigation.navigateTo(
+          {page: Page.LIST, type: extensions.ShowingType.APPS});
       expectEquals(manager.apps, manager.$['items-list'].items);
-      manager.listHelper_.showType(extensions.ShowingType.EXTENSIONS);
+      extensions.navigation.navigateTo(
+          {page: Page.LIST, type: extensions.ShowingType.EXTENSIONS});
       expectEquals(manager.extensions, manager.$['items-list'].items);
       // Repeating a selection should have no change.
-      manager.listHelper_.showType(extensions.ShowingType.EXTENSIONS);
+      extensions.navigation.navigateTo(
+          {page: Page.LIST, type: extensions.ShowingType.EXTENSIONS});
       expectEquals(manager.extensions, manager.$['items-list'].items);
     });
 
     test(assert(TestNames.ChangePages), function() {
       // We start on the item list.
-      MockInteractions.tap(manager.sidebar.$['sections-extensions']);
+      MockInteractions.tap(manager.$.sidebar.$['sections-extensions']);
       Polymer.dom.flush();
       isActiveView(Page.LIST);
 
       // Switch: item list -> keyboard shortcuts.
-      MockInteractions.tap(manager.sidebar.$['sections-shortcuts']);
+      MockInteractions.tap(manager.$.sidebar.$['sections-shortcuts']);
       Polymer.dom.flush();
       isActiveView(Page.SHORTCUTS);
 
       // Switch: keyboard shortcuts -> item list.
-      MockInteractions.tap(manager.sidebar.$['sections-apps']);
+      MockInteractions.tap(manager.$.sidebar.$['sections-apps']);
       Polymer.dom.flush();
       isActiveView(Page.LIST);
 
@@ -150,7 +153,7 @@
       isActiveView(Page.DETAILS);
 
       // Switch: detail view -> keyboard shortcuts.
-      MockInteractions.tap(manager.sidebar.$['sections-shortcuts']);
+      MockInteractions.tap(manager.$.sidebar.$['sections-shortcuts']);
       Polymer.dom.flush();
       isActiveView(Page.SHORTCUTS);
     });
diff --git a/chrome/test/data/webui/extensions/extension_navigation_helper_test.js b/chrome/test/data/webui/extensions/extension_navigation_helper_test.js
index 0390aca5..f7e3d30 100644
--- a/chrome/test/data/webui/extensions/extension_navigation_helper_test.js
+++ b/chrome/test/data/webui/extensions/extension_navigation_helper_test.js
@@ -36,18 +36,20 @@
       var changePage = function(state) {
         mock.recordCall([state]);
       };
-      var navigationHelper = new extensions.NavigationHelper(changePage);
+
+      extensions.navigation.onRouteChanged(changePage);
 
       expectEquals('chrome://extensions/navigation_helper.html', location.href);
       expectDeepEquals(
           {page: Page.LIST, type: extensions.ShowingType.EXTENSIONS},
-          navigationHelper.getCurrentPage());
+          extensions.navigation.getCurrentPage());
 
       var currentLength = history.length;
-      navigationHelper.updateHistory({page: Page.DETAILS, extensionId: id});
+      extensions.navigation.updateHistory(
+          {page: Page.DETAILS, extensionId: id});
       expectEquals(++currentLength, history.length);
 
-      navigationHelper.updateHistory({page: Page.ERRORS, extensionId: id});
+      extensions.navigation.updateHistory({page: Page.ERRORS, extensionId: id});
       expectEquals(++currentLength, history.length);
 
       mock.addExpectation({page: Page.DETAILS, extensionId: id});
@@ -101,19 +103,18 @@
         },
       };
 
-      var navigationHelper = new extensions.NavigationHelper(function() {});
-
       // Test url -> state.
       for (let key in stateUrlPairs) {
         let entry = stateUrlPairs[key];
         history.pushState({}, '', entry.url);
-        expectDeepEquals(entry.state, navigationHelper.getCurrentPage(), key);
+        expectDeepEquals(
+            entry.state, extensions.navigation.getCurrentPage(), key);
       }
 
       // Test state -> url.
       for (let key in stateUrlPairs) {
         let entry = stateUrlPairs[key];
-        navigationHelper.updateHistory(entry.state);
+        extensions.navigation.updateHistory(entry.state);
         expectEquals(entry.url, location.href, key);
       }
     });
@@ -121,42 +122,44 @@
     test(assert(TestNames.PushAndReplaceState), function() {
       var id1 = 'a'.repeat(32);
       var id2 = 'b'.repeat(32);
-      var navigationHelper = new extensions.NavigationHelper(function() {});
 
       history.pushState({}, '', 'chrome://extensions/');
       expectDeepEquals(
           {page: Page.LIST, type: extensions.ShowingType.EXTENSIONS},
-          navigationHelper.getCurrentPage());
+          extensions.navigation.getCurrentPage());
 
       var expectedLength = history.length;
 
       // Navigating to a new page pushes new state.
-      navigationHelper.updateHistory({page: Page.DETAILS, extensionId: id1});
+      extensions.navigation.updateHistory(
+          {page: Page.DETAILS, extensionId: id1});
       expectEquals(++expectedLength, history.length);
 
       // Navigating to a subpage (like the options page) just opens a dialog,
       // and shouldn't push new state.
-      navigationHelper.updateHistory(
+      extensions.navigation.updateHistory(
           {page: Page.DETAILS, extensionId: id1, subpage: Dialog.OPTIONS});
       expectEquals(expectedLength, history.length);
 
       // Navigating away from a subpage also shouldn't push state (it just
       // closes the dialog).
-      navigationHelper.updateHistory({page: Page.DETAILS, extensionId: id1});
+      extensions.navigation.updateHistory(
+          {page: Page.DETAILS, extensionId: id1});
       expectEquals(expectedLength, history.length);
 
       // Navigating away should push new state.
-      navigationHelper.updateHistory({page: Page.LIST});
+      extensions.navigation.updateHistory({page: Page.LIST});
       expectEquals(++expectedLength, history.length);
 
       // Navigating to a subpage of a different page should push state.
-      navigationHelper.updateHistory(
+      extensions.navigation.updateHistory(
           {page: Page.DETAILS, extensionId: id1, subpage: Dialog.OPTIONS});
       expectEquals(++expectedLength, history.length);
 
       // Navigating away from a subpage to a page for a different item should
       // push state.
-      navigationHelper.updateHistory({page: Page.DETAILS, extensionId: id2});
+      extensions.navigation.updateHistory(
+          {page: Page.DETAILS, extensionId: id2});
       expectEquals(++expectedLength, history.length);
     });
   });
diff --git a/chrome/test/data/webui/extensions/extension_sidebar_test.js b/chrome/test/data/webui/extensions/extension_sidebar_test.js
index 8b9f666..15c66c5 100644
--- a/chrome/test/data/webui/extensions/extension_sidebar_test.js
+++ b/chrome/test/data/webui/extensions/extension_sidebar_test.js
@@ -4,33 +4,12 @@
 
 /** @fileoverview Suite of tests for extension-sidebar. */
 cr.define('extension_sidebar_tests', function() {
-  /**
-   * A mock delegate for the sidebar.
-   * @constructor
-   * @implements {extensions.SidebarListDelegate}
-   * @extends {extension_test_util.ClickMock}
-   */
-  function MockDelegate() {}
-
-  MockDelegate.prototype = {
-    __proto__: extension_test_util.ClickMock.prototype,
-
-    /** @override */
-    showType: function() {},
-
-    /** @override */
-    showKeyboardShortcuts: function() {},
-  };
-
   /** @enum {string} */
   var TestNames = {
     LayoutAndClickHandlers: 'layout and click handlers',
   };
 
   suite('ExtensionSidebarTest', function() {
-    /** @type {MockDelegate} */
-    var mockDelegate;
-
     /** @type {extensions.Sidebar} */
     var sidebar;
 
@@ -42,9 +21,7 @@
     setup(function() {
       var manager = document.querySelector('extensions-manager');
       manager.$.drawer.openDrawer();
-      sidebar = manager.sidebar;
-      mockDelegate = new MockDelegate();
-      sidebar.setListDelegate(mockDelegate);
+      sidebar = manager.$.sidebar;
     });
 
     test(assert(TestNames.LayoutAndClickHandlers), function() {
@@ -56,14 +33,22 @@
       testVisible('#sections-shortcuts', true);
       testVisible('#more-extensions', true);
 
-      mockDelegate.testClickingCalls(
-          sidebar.$$('#sections-extensions'), 'showType',
-          [extensions.ShowingType.EXTENSIONS]);
-      mockDelegate.testClickingCalls(
-          sidebar.$$('#sections-apps'), 'showType',
-          [extensions.ShowingType.APPS]);
-      mockDelegate.testClickingCalls(
-          sidebar.$$('#sections-shortcuts'), 'showKeyboardShortcuts', []);
+      var currentPage;
+      extensions.navigation.onRouteChanged(newPage => {
+        currentPage = newPage;
+      });
+
+      MockInteractions.tap(sidebar.$$('#sections-apps'));
+      expectDeepEquals(
+          currentPage, {page: Page.LIST, type: extensions.ShowingType.APPS});
+
+      MockInteractions.tap(sidebar.$$('#sections-extensions'));
+      expectDeepEquals(
+          currentPage,
+          {page: Page.LIST, type: extensions.ShowingType.EXTENSIONS});
+
+      MockInteractions.tap(sidebar.$$('#sections-shortcuts'));
+      expectDeepEquals(currentPage, {page: Page.SHORTCUTS});
     });
   });
 
diff --git a/chrome/test/data/webui/settings/bluetooth_page_tests.js b/chrome/test/data/webui/settings/bluetooth_page_tests.js
index afda0af..e118fc0 100644
--- a/chrome/test/data/webui/settings/bluetooth_page_tests.js
+++ b/chrome/test/data/webui/settings/bluetooth_page_tests.js
@@ -118,7 +118,10 @@
       assertTrue(!!subpage);
     });
 
-    test('toggle', function() {
+    // Skipping all SubPage tests as this is currently flaky.
+    // TODO(sonnysasaka): re-enable these tests once the flakiness is fixed
+    // (http://crbug.com/756283).
+    test.skip('toggle', function() {
       assertTrue(bluetoothPage.prefs.ash.user.bluetooth.adapter_enabled.value);
 
       var enableButton = subpage.$.enableBluetooth;
@@ -132,7 +135,7 @@
       assertFalse(bluetoothPage.prefs.ash.user.bluetooth.adapter_enabled.value);
     });
 
-    test('paired device list', function() {
+    test.skip('paired device list', function() {
       assertTrue(subpage.adapterState.powered);
 
       var pairedContainer = subpage.$.pairedContainer;
@@ -156,7 +159,7 @@
       assertFalse(devices[1].device.connected);
     });
 
-    test('unpaired device list', function() {
+    test.skip('unpaired device list', function() {
       assertTrue(subpage.adapterState.powered);
 
       var unpairedContainer = subpage.$.unpairedContainer;
@@ -180,7 +183,7 @@
       assertFalse(devices[1].device.paired);
     });
 
-    test('pair device', function(done) {
+    test.skip('pair device', function(done) {
       assertTrue(subpage.adapterState.powered);
 
       bluetoothApi_.setDevicesForTest(fakeDevices_);
@@ -198,7 +201,7 @@
       });
     });
 
-    test('pair dialog', function() {
+    test.skip('pair dialog', function() {
       assertTrue(subpage.adapterState.powered);
 
       bluetoothApi_.setDevicesForTest(fakeDevices_);
diff --git a/chrome/test/data/webui/settings/site_data_test.js b/chrome/test/data/webui/settings/site_data_test.js
index 74c9cfb9..80ec619a 100644
--- a/chrome/test/data/webui/settings/site_data_test.js
+++ b/chrome/test/data/webui/settings/site_data_test.js
@@ -36,22 +36,18 @@
     Polymer.dom.flush();
     assertEquals(
         siteData.sites.length,
-        siteData.shadowRoot.querySelectorAll('.list-item').length);
+        siteData.shadowRoot.querySelectorAll('#siteItem').length);
 
     // Expecting one result, so the button should be shown.
-    siteData.$.filter.dispatchEvent(
-        new CustomEvent('search-changed', {detail: 'Hello'}));
+    siteData.filter = 'Hello';
     Polymer.dom.flush();
-    assertEquals(
-        1, siteData.shadowRoot.querySelectorAll('.list-item').length);
+    assertEquals(1, siteData.shadowRoot.querySelectorAll('#siteItem').length);
     assertFalse(siteData.$.removeShowingSites.hidden);
 
     // Expecting no results, so the button should be hidden.
-    siteData.$.filter.dispatchEvent(
-        new CustomEvent('search-changed', {detail: 'foo'}));
+    siteData.filter = 'foo';
     Polymer.dom.flush();
-    assertEquals(
-        0, siteData.shadowRoot.querySelectorAll('.list-item').length);
+    assertEquals(0, siteData.shadowRoot.querySelectorAll('#siteItem').length);
     assertTrue(siteData.$.removeShowingSites.hidden);
   });
 });
diff --git a/chrome/test/vr/perf/latency/webvr_latency_test.py b/chrome/test/vr/perf/latency/webvr_latency_test.py
index 518bdd9..d2b2e08 100644
--- a/chrome/test/vr/perf/latency/webvr_latency_test.py
+++ b/chrome/test/vr/perf/latency/webvr_latency_test.py
@@ -186,7 +186,10 @@
 
   def _SaveResultsToFile(self):
     outpath = None
-    if (hasattr(self._args, 'isolated_script_test_chartjson_output') and
+    if (hasattr(self._args, 'isolated_script_test_perf_output') and
+        self._args.isolated_script_test_perf_output):
+      outpath = self._args.isolated_script_test_perf_output
+    elif (hasattr(self._args, 'isolated_script_test_chartjson_output') and
         self._args.isolated_script_test_chartjson_output):
       outpath = self._args.isolated_script_test_chartjson_output
     else:
diff --git a/chrome/test/vr/perf/vrcore_fps/vrcore_fps_test.py b/chrome/test/vr/perf/vrcore_fps/vrcore_fps_test.py
index c0dbfce..5433d73 100644
--- a/chrome/test/vr/perf/vrcore_fps/vrcore_fps_test.py
+++ b/chrome/test/vr/perf/vrcore_fps/vrcore_fps_test.py
@@ -81,7 +81,10 @@
 
   def _SaveResultsToFile(self):
     outpath = None
-    if (hasattr(self._args, 'isolated_script_test_chartjson_output') and
+    if (hasattr(self._args, 'isolated_script_test_perf_output') and
+        self._args.isolated_script_test_perf_output):
+      outpath = self._args.isolated_script_test_perf_output
+    elif (hasattr(self._args, 'isolated_script_test_chartjson_output') and
         self._args.isolated_script_test_chartjson_output):
       outpath = self._args.isolated_script_test_chartjson_output
     else:
diff --git a/chromecast/media/service/cast_mojo_media_client.cc b/chromecast/media/service/cast_mojo_media_client.cc
index 468a40e..130aefb 100644
--- a/chromecast/media/service/cast_mojo_media_client.cc
+++ b/chromecast/media/service/cast_mojo_media_client.cc
@@ -115,7 +115,9 @@
 
 CastMojoMediaClient::~CastMojoMediaClient() {}
 
-void CastMojoMediaClient::Initialize(service_manager::Connector* connector) {
+void CastMojoMediaClient::Initialize(
+    service_manager::Connector* connector,
+    service_manager::ServiceContextRefFactory* context_ref_factory) {
   DCHECK(!connector_);
   DCHECK(connector);
   connector_ = connector;
diff --git a/chromecast/media/service/cast_mojo_media_client.h b/chromecast/media/service/cast_mojo_media_client.h
index 521507b..a2709d9 100644
--- a/chromecast/media/service/cast_mojo_media_client.h
+++ b/chromecast/media/service/cast_mojo_media_client.h
@@ -28,7 +28,9 @@
   ~CastMojoMediaClient() override;
 
   // MojoMediaClient overrides.
-  void Initialize(service_manager::Connector* connector) override;
+  void Initialize(
+      service_manager::Connector* connector,
+      service_manager::ServiceContextRefFactory* context_ref_factory) override;
   scoped_refptr<::media::AudioRendererSink> CreateAudioRendererSink(
       const std::string& audio_device_id) override;
   std::unique_ptr<::media::RendererFactory> CreateRendererFactory(
diff --git a/chromeos/components/tether/fake_notification_presenter.cc b/chromeos/components/tether/fake_notification_presenter.cc
index 5851b30..1c53d34 100644
--- a/chromeos/components/tether/fake_notification_presenter.cc
+++ b/chromeos/components/tether/fake_notification_presenter.cc
@@ -15,7 +15,8 @@
 FakeNotificationPresenter::FakeNotificationPresenter()
     : NotificationPresenter(),
       potential_hotspot_state_(
-          PotentialHotspotNotificationState::NO_HOTSPOT_NOTIFICATION_SHOWN),
+          NotificationPresenter::PotentialHotspotNotificationState::
+              NO_HOTSPOT_NOTIFICATION_SHOWN),
       is_setup_required_notification_shown_(false),
       is_connection_failed_notification_shown_(false) {}
 
@@ -23,26 +24,32 @@
 
 cryptauth::RemoteDevice&
 FakeNotificationPresenter::GetPotentialHotspotRemoteDevice() {
-  EXPECT_EQ(PotentialHotspotNotificationState::SINGLE_HOTSPOT_NEARBY_SHOWN,
-            potential_hotspot_state_);
+  EXPECT_EQ(potential_hotspot_state_,
+            NotificationPresenter::PotentialHotspotNotificationState::
+                SINGLE_HOTSPOT_NEARBY_SHOWN);
   return potential_hotspot_remote_device_;
 }
 
 void FakeNotificationPresenter::NotifyPotentialHotspotNearby(
     const cryptauth::RemoteDevice& remote_device,
     int signal_strength) {
-  potential_hotspot_state_ =
+  potential_hotspot_state_ = NotificationPresenter::
       PotentialHotspotNotificationState::SINGLE_HOTSPOT_NEARBY_SHOWN;
   potential_hotspot_remote_device_ = remote_device;
 }
 
 void FakeNotificationPresenter::NotifyMultiplePotentialHotspotsNearby() {
-  potential_hotspot_state_ =
+  potential_hotspot_state_ = NotificationPresenter::
       PotentialHotspotNotificationState::MULTIPLE_HOTSPOTS_NEARBY_SHOWN;
 }
 
+NotificationPresenter::PotentialHotspotNotificationState
+FakeNotificationPresenter::GetPotentialHotspotNotificationState() {
+  return potential_hotspot_state_;
+}
+
 void FakeNotificationPresenter::RemovePotentialHotspotNotification() {
-  potential_hotspot_state_ =
+  potential_hotspot_state_ = NotificationPresenter::
       PotentialHotspotNotificationState::NO_HOTSPOT_NOTIFICATION_SHOWN;
 }
 
diff --git a/chromeos/components/tether/fake_notification_presenter.h b/chromeos/components/tether/fake_notification_presenter.h
index 5e47a31..f03260a 100644
--- a/chromeos/components/tether/fake_notification_presenter.h
+++ b/chromeos/components/tether/fake_notification_presenter.h
@@ -17,19 +17,9 @@
 
 class FakeNotificationPresenter : public NotificationPresenter {
  public:
-  enum class PotentialHotspotNotificationState {
-    SINGLE_HOTSPOT_NEARBY_SHOWN,
-    MULTIPLE_HOTSPOTS_NEARBY_SHOWN,
-    NO_HOTSPOT_NOTIFICATION_SHOWN
-  };
-
   FakeNotificationPresenter();
   ~FakeNotificationPresenter() override;
 
-  PotentialHotspotNotificationState potential_hotspot_state() {
-    return potential_hotspot_state_;
-  }
-
   // Note: This function fails a test if potential_hotspot_state() is not
   // SINGLE_HOTSPOT_NEARBY_SHOWN when called.
   cryptauth::RemoteDevice& GetPotentialHotspotRemoteDevice();
@@ -51,6 +41,8 @@
       const cryptauth::RemoteDevice& remote_device,
       int signal_strength) override;
   void NotifyMultiplePotentialHotspotsNearby() override;
+  PotentialHotspotNotificationState GetPotentialHotspotNotificationState()
+      override;
   void RemovePotentialHotspotNotification() override;
   void NotifySetupRequired(const std::string& device_name) override;
   void RemoveSetupRequiredNotification() override;
diff --git a/chromeos/components/tether/host_scanner.cc b/chromeos/components/tether/host_scanner.cc
index 570b6ba..e184c50 100644
--- a/chromeos/components/tether/host_scanner.cc
+++ b/chromeos/components/tether/host_scanner.cc
@@ -75,15 +75,24 @@
     std::vector<HostScannerOperation::ScannedDeviceInfo>&
         scanned_device_list_so_far,
     bool is_final_scan_result) {
+  if (scanned_device_list_so_far.empty() && !is_final_scan_result) {
+    was_notification_showing_when_current_scan_started_ =
+        IsPotentialHotspotNotificationShowing();
+  }
+
   // Ensure all results received so far are in the cache (setting entries which
   // already exist is a no-op).
   for (const auto& scanned_device_info : scanned_device_list_so_far) {
     SetCacheEntry(scanned_device_info);
   }
 
-  if (!network_state_handler_->DefaultNetwork() &&
+  if (CanAvailableHostNotificationBeShown() &&
       !scanned_device_list_so_far.empty()) {
-    if (scanned_device_list_so_far.size() == 1u) {
+    if (scanned_device_list_so_far.size() == 1u &&
+        (notification_presenter_->GetPotentialHotspotNotificationState() !=
+             NotificationPresenter::PotentialHotspotNotificationState::
+                 MULTIPLE_HOTSPOTS_NEARBY_SHOWN ||
+         is_final_scan_result)) {
       const cryptauth::RemoteDevice& remote_device =
           scanned_device_list_so_far.at(0).remote_device;
       int32_t signal_strength;
@@ -99,7 +108,7 @@
       notification_presenter_->NotifyMultiplePotentialHotspotsNearby();
     }
 
-    was_available_hotspot_notification_shown_ = true;
+    was_notification_shown_in_current_scan_ = true;
   }
 
   if (is_final_scan_result) {
@@ -169,7 +178,7 @@
 
   if (final_scan_results.empty()) {
     RecordHostScanResult(HostScanResultEventType::NO_HOSTS_FOUND);
-  } else if (!was_available_hotspot_notification_shown_) {
+  } else if (!was_notification_shown_in_current_scan_) {
     RecordHostScanResult(
         HostScanResultEventType::HOSTS_FOUND_BUT_NO_NOTIFICATION_SHOWN);
   } else if (final_scan_results.size() == 1u) {
@@ -179,7 +188,10 @@
     RecordHostScanResult(
         HostScanResultEventType::NOTIFICATION_SHOWN_MULTIPLE_HOSTS);
   }
-  was_available_hotspot_notification_shown_ = false;
+  has_notification_been_shown_in_previous_scan_ |=
+      was_notification_shown_in_current_scan_;
+  was_notification_shown_in_current_scan_ = false;
+  was_notification_showing_when_current_scan_started_ = false;
 
   // If the final scan result has been received, the operation is finished.
   // Delete it.
@@ -195,6 +207,53 @@
                             HostScanResultEventType::HOST_SCAN_RESULT_MAX);
 }
 
+bool HostScanner::IsPotentialHotspotNotificationShowing() {
+  return notification_presenter_->GetPotentialHotspotNotificationState() !=
+         NotificationPresenter::PotentialHotspotNotificationState::
+             NO_HOTSPOT_NOTIFICATION_SHOWN;
+}
+
+bool HostScanner::CanAvailableHostNotificationBeShown() {
+  // Note: If a network is active (i.e., connecting or connected), it will be
+  // returned at the front of the list, so using FirstNetworkByType() guarantees
+  // that we will find an active network if there is one.
+  const chromeos::NetworkState* first_network =
+      network_state_handler_->FirstNetworkByType(
+          chromeos::NetworkTypePattern::Default());
+  if (first_network && first_network->IsConnectingOrConnected()) {
+    // If a network is connecting or connected, the notification should not be
+    // shown.
+    return false;
+  }
+
+  if (!IsPotentialHotspotNotificationShowing() &&
+      was_notification_shown_in_current_scan_) {
+    // If a notification was shown in the current scan but it is no longer
+    // showing, it has been removed, either due to NotificationRemover or due to
+    // the user closing it. Since a scan only lasts on the order of seconds to
+    // tens of seconds, we know that the notification was very recently closed,
+    // so we should not re-show it.
+    return false;
+  }
+
+  if (!IsPotentialHotspotNotificationShowing() &&
+      was_notification_showing_when_current_scan_started_) {
+    // If a notification was showing when the scan started but is no longer
+    // showing, it has been removed and should not be re-shown.
+    return false;
+  }
+
+  if (has_notification_been_shown_in_previous_scan_ &&
+      !was_notification_showing_when_current_scan_started_) {
+    // If a notification was shown in a previous scan but was not visible when
+    // the current scan started, it should not be shown because this could be
+    // considered spammy; see crbug.com/759078.
+    return false;
+  }
+
+  return true;
+}
+
 }  // namespace tether
 
 }  // namespace chromeos
diff --git a/chromeos/components/tether/host_scanner.h b/chromeos/components/tether/host_scanner.h
index d2ef16f7..c00673d 100644
--- a/chromeos/components/tether/host_scanner.h
+++ b/chromeos/components/tether/host_scanner.h
@@ -90,6 +90,8 @@
   void OnFinalScanResultReceived(
       std::vector<HostScannerOperation::ScannedDeviceInfo>& final_scan_results);
   void RecordHostScanResult(HostScanResultEventType event_type);
+  bool IsPotentialHotspotNotificationShowing();
+  bool CanAvailableHostNotificationBeShown();
 
   NetworkStateHandler* network_state_handler_;
   TetherHostFetcher* tether_host_fetcher_;
@@ -102,7 +104,9 @@
   base::Clock* clock_;
 
   bool is_fetching_hosts_ = false;
-  bool was_available_hotspot_notification_shown_ = false;
+  bool was_notification_showing_when_current_scan_started_ = false;
+  bool was_notification_shown_in_current_scan_ = false;
+  bool has_notification_been_shown_in_previous_scan_ = false;
   std::unique_ptr<HostScannerOperation> host_scanner_operation_;
   std::unordered_set<std::string> tether_guids_in_cache_before_scan_;
 
diff --git a/chromeos/components/tether/host_scanner_unittest.cc b/chromeos/components/tether/host_scanner_unittest.cc
index 98f47776..2b15133 100644
--- a/chromeos/components/tether/host_scanner_unittest.cc
+++ b/chromeos/components/tether/host_scanner_unittest.cc
@@ -8,7 +8,6 @@
 #include <memory>
 #include <vector>
 
-#include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
 #include "base/test/histogram_tester.h"
@@ -245,7 +244,8 @@
       FakeHostScannerOperation& fake_operation,
       size_t test_device_index,
       bool is_final_scan_result,
-      bool is_connected_to_internet) {
+      NotificationPresenter::PotentialHotspotNotificationState
+          expected_notification_state) {
     bool already_in_list = false;
     for (auto& scanned_device_info : scanned_device_infos_from_current_scan_) {
       if (scanned_device_info.remote_device.GetDeviceId() ==
@@ -267,25 +267,17 @@
     EXPECT_EQ(previous_scan_finished_count + (is_final_scan_result ? 1 : 0),
               test_observer_->scan_finished_count());
 
-    if (is_connected_to_internet) {
-      EXPECT_EQ(FakeNotificationPresenter::PotentialHotspotNotificationState::
-                    NO_HOTSPOT_NOTIFICATION_SHOWN,
-                fake_notification_presenter_->potential_hotspot_state());
-    } else if (scanned_device_infos_from_current_scan_.size() == 1) {
-      EXPECT_EQ(FakeNotificationPresenter::PotentialHotspotNotificationState::
-                    SINGLE_HOTSPOT_NEARBY_SHOWN,
-                fake_notification_presenter_->potential_hotspot_state());
-    } else {
-      EXPECT_EQ(FakeNotificationPresenter::PotentialHotspotNotificationState::
-                    MULTIPLE_HOTSPOTS_NEARBY_SHOWN,
-                fake_notification_presenter_->potential_hotspot_state());
-    }
+    EXPECT_EQ(
+        expected_notification_state,
+        fake_notification_presenter_->GetPotentialHotspotNotificationState());
 
     if (is_final_scan_result) {
       HostScanner::HostScanResultEventType expected_event_type =
           HostScanner::HostScanResultEventType::NO_HOSTS_FOUND;
       if (!scanned_device_infos_from_current_scan_.empty() &&
-          is_connected_to_internet) {
+          expected_notification_state ==
+              NotificationPresenter::PotentialHotspotNotificationState::
+                  NO_HOTSPOT_NOTIFICATION_SHOWN) {
         expected_event_type = HostScanner::HostScanResultEventType::
             HOSTS_FOUND_BUT_NO_NOTIFICATION_SHOWN;
       } else if (scanned_device_infos_from_current_scan_.size() == 1) {
@@ -366,12 +358,12 @@
     scanned_device_infos_from_current_scan_.clear();
   }
 
-  void ConnectToWifiNetwork() {
+  void StartConnectingToWifiNetwork() {
     std::stringstream ss;
     ss << "{"
        << "  \"GUID\": \"wifiNetworkGuid\","
        << "  \"Type\": \"" << shill::kTypeWifi << "\","
-       << "  \"State\": \"" << shill::kStateOnline << "\""
+       << "  \"State\": \"" << shill::kStateConfiguration << "\""
        << "}";
 
     ConfigureService(ss.str());
@@ -413,8 +405,8 @@
   DISALLOW_COPY_AND_ASSIGN(HostScannerTest);
 };
 
-TEST_F(HostScannerTest, TestScan_ConnectedToExistingNetwork) {
-  ConnectToWifiNetwork();
+TEST_F(HostScannerTest, TestScan_ConnectingToExistingNetwork) {
+  StartConnectingToWifiNetwork();
   EXPECT_TRUE(network_state_handler()->DefaultNetwork());
 
   EXPECT_FALSE(host_scanner_->IsScanActive());
@@ -429,22 +421,65 @@
   ReceiveScanResultAndVerifySuccess(
       *fake_host_scanner_operation_factory_->created_operations()[0],
       0u /* test_device_index */, false /* is_final_scan_result */,
-      true /* is_connected_to_internet */);
+      NotificationPresenter::PotentialHotspotNotificationState::
+          NO_HOTSPOT_NOTIFICATION_SHOWN);
   EXPECT_TRUE(host_scanner_->IsScanActive());
   ReceiveScanResultAndVerifySuccess(
       *fake_host_scanner_operation_factory_->created_operations()[0],
       1u /* test_device_index */, false /* is_final_scan_result */,
-      true /* is_connected_to_internet */);
+      NotificationPresenter::PotentialHotspotNotificationState::
+          NO_HOTSPOT_NOTIFICATION_SHOWN);
   EXPECT_TRUE(host_scanner_->IsScanActive());
   ReceiveScanResultAndVerifySuccess(
       *fake_host_scanner_operation_factory_->created_operations()[0],
       2u /* test_device_index */, false /* is_final_scan_result */,
-      true /* is_connected_to_internet */);
+      NotificationPresenter::PotentialHotspotNotificationState::
+          NO_HOTSPOT_NOTIFICATION_SHOWN);
   EXPECT_TRUE(host_scanner_->IsScanActive());
   ReceiveScanResultAndVerifySuccess(
       *fake_host_scanner_operation_factory_->created_operations()[0],
       3u /* test_device_index */, true /* is_final_scan_result */,
-      true /* is_connected_to_internet */);
+      NotificationPresenter::PotentialHotspotNotificationState::
+          NO_HOTSPOT_NOTIFICATION_SHOWN);
+  EXPECT_FALSE(host_scanner_->IsScanActive());
+}
+
+TEST_F(HostScannerTest, TestNotificationNotDisplayedMultipleTimes) {
+  StartConnectingToWifiNetwork();
+  EXPECT_TRUE(network_state_handler()->DefaultNetwork());
+
+  EXPECT_FALSE(host_scanner_->IsScanActive());
+  host_scanner_->StartScan();
+  EXPECT_TRUE(host_scanner_->IsScanActive());
+
+  fake_tether_host_fetcher_->InvokePendingCallbacks();
+  ASSERT_EQ(1u,
+            fake_host_scanner_operation_factory_->created_operations().size());
+  EXPECT_TRUE(host_scanner_->IsScanActive());
+
+  ReceiveScanResultAndVerifySuccess(
+      *fake_host_scanner_operation_factory_->created_operations()[0],
+      0u /* test_device_index */, false /* is_final_scan_result */,
+      NotificationPresenter::PotentialHotspotNotificationState::
+          NO_HOTSPOT_NOTIFICATION_SHOWN);
+  EXPECT_TRUE(host_scanner_->IsScanActive());
+  ReceiveScanResultAndVerifySuccess(
+      *fake_host_scanner_operation_factory_->created_operations()[0],
+      1u /* test_device_index */, false /* is_final_scan_result */,
+      NotificationPresenter::PotentialHotspotNotificationState::
+          NO_HOTSPOT_NOTIFICATION_SHOWN);
+  EXPECT_TRUE(host_scanner_->IsScanActive());
+  ReceiveScanResultAndVerifySuccess(
+      *fake_host_scanner_operation_factory_->created_operations()[0],
+      2u /* test_device_index */, false /* is_final_scan_result */,
+      NotificationPresenter::PotentialHotspotNotificationState::
+          NO_HOTSPOT_NOTIFICATION_SHOWN);
+  EXPECT_TRUE(host_scanner_->IsScanActive());
+  ReceiveScanResultAndVerifySuccess(
+      *fake_host_scanner_operation_factory_->created_operations()[0],
+      3u /* test_device_index */, true /* is_final_scan_result */,
+      NotificationPresenter::PotentialHotspotNotificationState::
+          NO_HOTSPOT_NOTIFICATION_SHOWN);
   EXPECT_FALSE(host_scanner_->IsScanActive());
 }
 
@@ -461,22 +496,26 @@
   ReceiveScanResultAndVerifySuccess(
       *fake_host_scanner_operation_factory_->created_operations()[0],
       0u /* test_device_index */, false /* is_final_scan_result */,
-      false /* is_connected_to_internet */);
+      NotificationPresenter::PotentialHotspotNotificationState::
+          SINGLE_HOTSPOT_NEARBY_SHOWN);
   EXPECT_TRUE(host_scanner_->IsScanActive());
   ReceiveScanResultAndVerifySuccess(
       *fake_host_scanner_operation_factory_->created_operations()[0],
       1u /* test_device_index */, false /* is_final_scan_result */,
-      false /* is_connected_to_internet */);
+      NotificationPresenter::PotentialHotspotNotificationState::
+          MULTIPLE_HOTSPOTS_NEARBY_SHOWN);
   EXPECT_TRUE(host_scanner_->IsScanActive());
   ReceiveScanResultAndVerifySuccess(
       *fake_host_scanner_operation_factory_->created_operations()[0],
       2u /* test_device_index */, false /* is_final_scan_result */,
-      false /* is_connected_to_internet */);
+      NotificationPresenter::PotentialHotspotNotificationState::
+          MULTIPLE_HOTSPOTS_NEARBY_SHOWN);
   EXPECT_TRUE(host_scanner_->IsScanActive());
   ReceiveScanResultAndVerifySuccess(
       *fake_host_scanner_operation_factory_->created_operations()[0],
       3u /* test_device_index */, true /* is_final_scan_result */,
-      false /* is_connected_to_internet */);
+      NotificationPresenter::PotentialHotspotNotificationState::
+          MULTIPLE_HOTSPOTS_NEARBY_SHOWN);
   EXPECT_FALSE(host_scanner_->IsScanActive());
 }
 
@@ -516,12 +555,14 @@
   ReceiveScanResultAndVerifySuccess(
       *fake_host_scanner_operation_factory_->created_operations()[0],
       0u /* test_device_index */, false /* is_final_scan_result */,
-      false /* is_connected_to_internet */);
+      NotificationPresenter::PotentialHotspotNotificationState::
+          SINGLE_HOTSPOT_NEARBY_SHOWN);
   EXPECT_TRUE(host_scanner_->IsScanActive());
   ReceiveScanResultAndVerifySuccess(
       *fake_host_scanner_operation_factory_->created_operations()[0],
       1u /* test_device_index */, false /* is_final_scan_result */,
-      false /* is_connected_to_internet */);
+      NotificationPresenter::PotentialHotspotNotificationState::
+          MULTIPLE_HOTSPOTS_NEARBY_SHOWN);
   EXPECT_TRUE(host_scanner_->IsScanActive());
 
   fake_host_scanner_operation_factory_->created_operations()[0]
@@ -562,7 +603,8 @@
   ReceiveScanResultAndVerifySuccess(
       *fake_host_scanner_operation_factory_->created_operations()[0],
       0u /* test_device_index */, false /* is_final_scan_result */,
-      false /* is_connected_to_internet */);
+      NotificationPresenter::PotentialHotspotNotificationState::
+          SINGLE_HOTSPOT_NEARBY_SHOWN);
   EXPECT_TRUE(host_scanner_->IsScanActive());
 
   // Call StartScan again after a scan result has been received but before
@@ -599,17 +641,20 @@
   ReceiveScanResultAndVerifySuccess(
       *fake_host_scanner_operation_factory_->created_operations()[0],
       0u /* test_device_index */, false /* is_final_scan_result */,
-      false /* is_connected_to_internet */);
+      NotificationPresenter::PotentialHotspotNotificationState::
+          SINGLE_HOTSPOT_NEARBY_SHOWN);
   EXPECT_TRUE(host_scanner_->IsScanActive());
   ReceiveScanResultAndVerifySuccess(
       *fake_host_scanner_operation_factory_->created_operations()[0],
       1u /* test_device_index */, false /* is_final_scan_result */,
-      false /* is_connected_to_internet */);
+      NotificationPresenter::PotentialHotspotNotificationState::
+          MULTIPLE_HOTSPOTS_NEARBY_SHOWN);
   EXPECT_TRUE(host_scanner_->IsScanActive());
   ReceiveScanResultAndVerifySuccess(
       *fake_host_scanner_operation_factory_->created_operations()[0],
       2u /* test_device_index */, false /* is_final_scan_result */,
-      false /* is_connected_to_internet */);
+      NotificationPresenter::PotentialHotspotNotificationState::
+          MULTIPLE_HOTSPOTS_NEARBY_SHOWN);
   EXPECT_TRUE(host_scanner_->IsScanActive());
 
   // Finish the first scan.
@@ -620,7 +665,15 @@
             fake_host_scan_cache_->size());
   EXPECT_FALSE(host_scanner_->IsScanActive());
 
-  // Now, start the second scan session.
+  // The notification should still be visible.
+  EXPECT_EQ(
+      NotificationPresenter::PotentialHotspotNotificationState::
+          MULTIPLE_HOTSPOTS_NEARBY_SHOWN,
+      fake_notification_presenter_->GetPotentialHotspotNotificationState());
+
+  // Now, start the second scan session. Since the notification was still
+  // visible from the first scan session, it should still be able to be shown
+  // for the second scan session.
   ClearCurrentScanResults();
   EXPECT_FALSE(host_scanner_->IsScanActive());
   host_scanner_->StartScan();
@@ -634,28 +687,73 @@
   // The cache should be unaffected by the start of a new scan.
   VerifyScanResultsMatchCache();
 
+  // Receive results from devices 0 only. Results from devices 1 and 2 should
+  // still be present in the cache even though no results have been received
+  // from that device during this scan session.
+  ReceiveScanResultAndVerifySuccess(
+      *fake_host_scanner_operation_factory_->created_operations()[1],
+      0u /* test_device_index */, false /* is_final_scan_result */,
+      NotificationPresenter::PotentialHotspotNotificationState::
+          MULTIPLE_HOTSPOTS_NEARBY_SHOWN);
+  EXPECT_TRUE(host_scanner_->IsScanActive());
+  VerifyScanResultsMatchCache();
+
+  // Finish the second scan. Since results were not received from devices 1 or
+  // 2, previous results from those devices should now be removed from the
+  // cache.
+  fake_host_scanner_operation_factory_->created_operations()[1]
+      ->SendScannedDeviceListUpdate(scanned_device_infos_from_current_scan_,
+                                    true /* is_final_scan_result */);
+  EXPECT_FALSE(host_scanner_->IsScanActive());
+
+  // The notification should have been changed to a single hotspot. Remove it
+  // before starting the third scan session.
+  EXPECT_EQ(
+      NotificationPresenter::PotentialHotspotNotificationState::
+          SINGLE_HOTSPOT_NEARBY_SHOWN,
+      fake_notification_presenter_->GetPotentialHotspotNotificationState());
+  fake_notification_presenter_->RemovePotentialHotspotNotification();
+
+  // Now, start the third scan session. Since the notification was hidden before
+  // the session started, it should not be shown for this session.
+  ClearCurrentScanResults();
+  EXPECT_FALSE(host_scanner_->IsScanActive());
+  host_scanner_->StartScan();
+  EXPECT_TRUE(host_scanner_->IsScanActive());
+
+  fake_tether_host_fetcher_->InvokePendingCallbacks();
+  ASSERT_EQ(3u,
+            fake_host_scanner_operation_factory_->created_operations().size());
+  EXPECT_TRUE(host_scanner_->IsScanActive());
+
+  // The cache should be unaffected by the start of a new scan.
+  VerifyScanResultsMatchCache();
+
   // Receive results from devices 0, 2 and 3. Results from device 1 should still
   // be present in the cache even though no results have been received from that
   // device during this scan session.
   ReceiveScanResultAndVerifySuccess(
-      *fake_host_scanner_operation_factory_->created_operations()[1],
+      *fake_host_scanner_operation_factory_->created_operations()[2],
       0u /* test_device_index */, false /* is_final_scan_result */,
-      false /* is_connected_to_internet */);
+      NotificationPresenter::PotentialHotspotNotificationState::
+          NO_HOTSPOT_NOTIFICATION_SHOWN);
   EXPECT_TRUE(host_scanner_->IsScanActive());
   ReceiveScanResultAndVerifySuccess(
-      *fake_host_scanner_operation_factory_->created_operations()[1],
+      *fake_host_scanner_operation_factory_->created_operations()[2],
       2u /* test_device_index */, false /* is_final_scan_result */,
-      false /* is_connected_to_internet */);
+      NotificationPresenter::PotentialHotspotNotificationState::
+          NO_HOTSPOT_NOTIFICATION_SHOWN);
   ReceiveScanResultAndVerifySuccess(
-      *fake_host_scanner_operation_factory_->created_operations()[1],
+      *fake_host_scanner_operation_factory_->created_operations()[2],
       3u /* test_device_index */, false /* is_final_scan_result */,
-      false /* is_connected_to_internet */);
+      NotificationPresenter::PotentialHotspotNotificationState::
+          NO_HOTSPOT_NOTIFICATION_SHOWN);
   EXPECT_TRUE(host_scanner_->IsScanActive());
   VerifyScanResultsMatchCache();
 
   // Finish the second scan. Since results were not received from device 1,
-  // previous results from evice 1 should now be removed from the cache.
-  fake_host_scanner_operation_factory_->created_operations()[1]
+  // previous results from device 1 should now be removed from the cache.
+  fake_host_scanner_operation_factory_->created_operations()[2]
       ->SendScannedDeviceListUpdate(scanned_device_infos_from_current_scan_,
                                     true /* is_final_scan_result */);
   EXPECT_FALSE(host_scanner_->IsScanActive());
diff --git a/chromeos/components/tether/notification_presenter.h b/chromeos/components/tether/notification_presenter.h
index 1415443..86e6f21 100644
--- a/chromeos/components/tether/notification_presenter.h
+++ b/chromeos/components/tether/notification_presenter.h
@@ -16,6 +16,12 @@
 
 class NotificationPresenter {
  public:
+  enum class PotentialHotspotNotificationState {
+    SINGLE_HOTSPOT_NEARBY_SHOWN,
+    MULTIPLE_HOTSPOTS_NEARBY_SHOWN,
+    NO_HOTSPOT_NOTIFICATION_SHOWN
+  };
+
   NotificationPresenter() {}
   virtual ~NotificationPresenter() {}
 
@@ -29,6 +35,10 @@
   // tether hotspots.
   virtual void NotifyMultiplePotentialHotspotsNearby() = 0;
 
+  // Returns the state of the "potential hotspot(s)" notification.
+  virtual PotentialHotspotNotificationState
+  GetPotentialHotspotNotificationState() = 0;
+
   // Removes the notification created by either NotifyPotentialHotspotNearby()
   // or NotifyMultiplePotentialHotspotsNearby(), or does nothing if that
   // notification is not currently displayed.
diff --git a/chromeos/components/tether/notification_remover.cc b/chromeos/components/tether/notification_remover.cc
index 98e1332..92ace3a 100644
--- a/chromeos/components/tether/notification_remover.cc
+++ b/chromeos/components/tether/notification_remover.cc
@@ -43,8 +43,15 @@
   notification_presenter_->RemovePotentialHotspotNotification();
 }
 
-void NotificationRemover::DefaultNetworkChanged(const NetworkState* network) {
-  if (network)
+void NotificationRemover::NetworkConnectionStateChanged(
+    const NetworkState* network) {
+  // Note: If a network is active (i.e., connecting or connected), it will be
+  // returned at the front of the list, so using FirstNetworkByType() guarantees
+  // that we will find an active network if there is one.
+  const chromeos::NetworkState* first_network =
+      network_state_handler_->FirstNetworkByType(
+          chromeos::NetworkTypePattern::Default());
+  if (first_network && first_network->IsConnectingOrConnected())
     notification_presenter_->RemovePotentialHotspotNotification();
 }
 
diff --git a/chromeos/components/tether/notification_remover.h b/chromeos/components/tether/notification_remover.h
index 6c547c2..dcbe8d8 100644
--- a/chromeos/components/tether/notification_remover.h
+++ b/chromeos/components/tether/notification_remover.h
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifndef CHROMEOS_COMPONENTS_TETHER_NOTIFICATION_REMOVER_H_
+#define CHROMEOS_COMPONENTS_TETHER_NOTIFICATION_REMOVER_H_
+
 #include "chromeos/components/tether/active_host.h"
 #include "chromeos/components/tether/host_scan_cache.h"
 #include "chromeos/network/network_state_handler_observer.h"
@@ -34,7 +37,7 @@
   void OnCacheBecameEmpty() override;
 
   // NetworkStateHandlerObserver:
-  void DefaultNetworkChanged(const NetworkState* network) override;
+  void NetworkConnectionStateChanged(const NetworkState* network) override;
 
   // ActiveHost::Observer:
   void OnActiveHostChanged(
@@ -52,3 +55,5 @@
 }  // namespace tether
 
 }  // namespace chromeos
+
+#endif  // CHROMEOS_COMPONENTS_TETHER_NOTIFICATION_REMOVER_H_
diff --git a/chromeos/components/tether/notification_remover_unittest.cc b/chromeos/components/tether/notification_remover_unittest.cc
index 545cdf35..d27adc3 100644
--- a/chromeos/components/tether/notification_remover_unittest.cc
+++ b/chromeos/components/tether/notification_remover_unittest.cc
@@ -60,12 +60,12 @@
     EXPECT_TRUE(host_scan_cache_->empty());
   }
 
-  void ConnectToWifiNetwork() {
+  void StartConnectingToWifiNetwork() {
     std::stringstream ss;
     ss << "{"
        << "  \"GUID\": \"wifiNetworkGuid\","
        << "  \"Type\": \"" << shill::kTypeWifi << "\","
-       << "  \"State\": \"" << shill::kStateOnline << "\""
+       << "  \"State\": \"" << shill::kStateConfiguration << "\""
        << "}";
 
     ConfigureService(ss.str());
@@ -87,24 +87,24 @@
 TEST_F(NotificationRemoverTest, TestCacheBecameEmpty) {
   NotifyPotentialHotspotNearby();
   SetAndRemoveHostScanResult();
-  EXPECT_EQ(FakeNotificationPresenter::PotentialHotspotNotificationState::
+  EXPECT_EQ(NotificationPresenter::PotentialHotspotNotificationState::
                 NO_HOTSPOT_NOTIFICATION_SHOWN,
-            notification_presenter_->potential_hotspot_state());
+            notification_presenter_->GetPotentialHotspotNotificationState());
 
   notification_presenter_->NotifyMultiplePotentialHotspotsNearby();
   SetAndRemoveHostScanResult();
-  EXPECT_EQ(FakeNotificationPresenter::PotentialHotspotNotificationState::
+  EXPECT_EQ(NotificationPresenter::PotentialHotspotNotificationState::
                 NO_HOTSPOT_NOTIFICATION_SHOWN,
-            notification_presenter_->potential_hotspot_state());
+            notification_presenter_->GetPotentialHotspotNotificationState());
 }
 
-TEST_F(NotificationRemoverTest, TestConnectToWifiNetwork) {
+TEST_F(NotificationRemoverTest, TestStartConnectingToWifiNetwork) {
   NotifyPotentialHotspotNearby();
 
-  ConnectToWifiNetwork();
-  EXPECT_EQ(FakeNotificationPresenter::PotentialHotspotNotificationState::
+  StartConnectingToWifiNetwork();
+  EXPECT_EQ(NotificationPresenter::PotentialHotspotNotificationState::
                 NO_HOTSPOT_NOTIFICATION_SHOWN,
-            notification_presenter_->potential_hotspot_state());
+            notification_presenter_->GetPotentialHotspotNotificationState());
 }
 
 TEST_F(NotificationRemoverTest, TestTetherDisabled) {
@@ -113,9 +113,9 @@
   notification_presenter_->NotifyConnectionToHostFailed();
 
   notification_remover_.reset();
-  EXPECT_EQ(FakeNotificationPresenter::PotentialHotspotNotificationState::
+  EXPECT_EQ(NotificationPresenter::PotentialHotspotNotificationState::
                 NO_HOTSPOT_NOTIFICATION_SHOWN,
-            notification_presenter_->potential_hotspot_state());
+            notification_presenter_->GetPotentialHotspotNotificationState());
   EXPECT_FALSE(notification_presenter_->is_setup_required_notification_shown());
   EXPECT_FALSE(
       notification_presenter_->is_connection_failed_notification_shown());
@@ -125,15 +125,15 @@
   NotifyPotentialHotspotNearby();
 
   active_host_->SetActiveHostDisconnected();
-  EXPECT_EQ(FakeNotificationPresenter::PotentialHotspotNotificationState::
+  EXPECT_EQ(NotificationPresenter::PotentialHotspotNotificationState::
                 SINGLE_HOTSPOT_NEARBY_SHOWN,
-            notification_presenter_->potential_hotspot_state());
+            notification_presenter_->GetPotentialHotspotNotificationState());
 
   active_host_->SetActiveHostConnecting("testDeviceId",
                                         host_scan_test_util::kTetherGuid0);
-  EXPECT_EQ(FakeNotificationPresenter::PotentialHotspotNotificationState::
+  EXPECT_EQ(NotificationPresenter::PotentialHotspotNotificationState::
                 NO_HOTSPOT_NOTIFICATION_SHOWN,
-            notification_presenter_->potential_hotspot_state());
+            notification_presenter_->GetPotentialHotspotNotificationState());
 }
 
 }  // namespace tether
diff --git a/chromeos/network/network_state.cc b/chromeos/network/network_state.cc
index a3e59d75..07a875d 100644
--- a/chromeos/network/network_state.cc
+++ b/chromeos/network/network_state.cc
@@ -382,6 +382,11 @@
   return visible() && StateIsConnecting(connection_state_);
 }
 
+bool NetworkState::IsConnectingOrConnected() const {
+  return visible() && (StateIsConnecting(connection_state_) ||
+                       StateIsConnected(connection_state_));
+}
+
 bool NetworkState::IsReconnecting() const {
   return visible() && StateIsConnecting(connection_state_) &&
          StateIsConnected(last_connection_state_);
diff --git a/chromeos/network/network_state.h b/chromeos/network/network_state.h
index 18dba041..635cc76 100644
--- a/chromeos/network/network_state.h
+++ b/chromeos/network/network_state.h
@@ -133,6 +133,7 @@
   // Returns true if |connection_state_| is a connected/connecting state.
   bool IsConnectedState() const;
   bool IsConnectingState() const;
+  bool IsConnectingOrConnected() const;
 
   // Returns true if |last_connection_state_| is connected, and
   // |connection_state_| is connecting.
diff --git a/chromeos/network/network_state_handler.cc b/chromeos/network/network_state_handler.cc
index c8484cf..918184e 100644
--- a/chromeos/network/network_state_handler.cc
+++ b/chromeos/network/network_state_handler.cc
@@ -395,13 +395,7 @@
   if (!network_list_sorted_)
     SortNetworkList();  // Sort to ensure visible networks are listed first.
 
-  // If |type| matches Tether networks and at least one Tether network is
-  // present, return the first network (since it has been sorted already).
-  if (type.MatchesPattern(NetworkTypePattern::Tether()) &&
-      !tether_network_list_.empty()) {
-    return tether_network_list_[0]->AsNetworkState();
-  }
-
+  const NetworkState* first_network = nullptr;
   for (auto iter = network_list_.begin(); iter != network_list_.end(); ++iter) {
     const NetworkState* network = (*iter)->AsNetworkState();
     DCHECK(network);
@@ -409,10 +403,36 @@
       continue;
     if (!network->visible())
       break;
-    if (network->Matches(type))
-      return network;
+    if (network->Matches(type)) {
+      first_network = network;
+      break;
+    }
   }
-  return nullptr;
+
+  // Active Ethernet networks are the highest priority.
+  if (first_network && first_network->type() == shill::kTypeEthernet)
+    return first_network;
+
+  const NetworkState* first_tether_network =
+      type.MatchesPattern(NetworkTypePattern::Tether()) &&
+              !tether_network_list_.empty()
+          ? tether_network_list_[0]->AsNetworkState()
+          : nullptr;
+
+  // Active Tether networks are next.
+  if (first_tether_network && first_tether_network->IsConnectingOrConnected())
+    return first_tether_network;
+
+  // Other active networks are next.
+  if (first_network && first_network->IsConnectingOrConnected())
+    return first_network;
+
+  // Non-active Tether networks are next.
+  if (first_tether_network)
+    return first_tether_network;
+
+  // Other networks are last.
+  return first_network;
 }
 
 std::string NetworkStateHandler::FormattedHardwareAddressForType(
diff --git a/components/BUILD.gn b/components/BUILD.gn
index 78d42f5..3592db0 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -322,8 +322,28 @@
     deps += [ "//components/safe_browsing/db:unit_tests_mobile" ]
   }
 
+  # No components should depend on Chrome.
+  if (is_chromeos) {
+    # TODO(bug 758767): //chromeos depends on a target in //chrome, and this
+    # target indirectly on //chromeos. The //chromeos -> //chrome dependency
+    # should be fixed and all of chrome added to the assert_no_deps.
+    #
+    # Until this case is fixed, we can blacklist the main Chrome targets which
+    # aren't actually used. This should prevent most major regressions.
+    assert_no_deps = [
+      "//chrome:*",  # Catches targets in this file and not subdirs.
+      "//chrome/browser",  # No * due to //chrome/browser/chromeos mess.
+      "//chrome/common/*",
+      "//chrome/renderer/*",
+      "//chrome/test/*",
+    ]
+  } else {
+    # Other platforms have clean dependencies.
+    assert_no_deps = [ "//chrome/*" ]
+  }
+
   if (is_ios) {
-    assert_no_deps = ios_assert_no_deps
+    assert_no_deps += ios_assert_no_deps
   }
 }
 
@@ -491,6 +511,23 @@
       sources += [ "printing/test/print_render_frame_helper_browsertest.cc" ]
       deps += [ "//components/printing/test:test_support" ]
     }
+
+    if (is_chromeos) {
+      # TODO(bug 758767): //chromeos depends on a target in //chrome, and this
+      # target indirectly on //chromeos. The //chromeos -> //chrome dependency
+      # should be fixed and all of chrome added to the assert_no_deps. For
+      # now, blacklist large parts of Chrome to prevent the most obvious
+      # regressions.
+      assert_no_deps = [
+        "//chrome:*",  # Catches targets in this file and not subdirs.
+        "//chrome/browser",  # No * due to //chrome/browser/chromeos problem.
+        "//chrome/common/*",
+        "//chrome/renderer/*",
+        "//chrome/test/*",
+      ]
+    } else {
+      assert_no_deps = [ "//chrome/*" ]
+    }
   }
 
   test("components_perftests") {
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 9f87219..e79d4b0 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
@@ -7,6 +7,7 @@
 import android.util.SparseArray;
 import android.view.ViewGroup;
 import android.view.ViewStructure;
+import android.view.autofill.AutofillValue;
 
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
@@ -42,7 +43,7 @@
      * @param values the array of autofill values, the key is virtual id of form
      *            field.
      */
-    public abstract void autofill(final SparseArray<Object> values);
+    public abstract void autofill(final SparseArray<AutofillValue> values);
 
     /**
      * Invoked when autofill service needs the form structure.
diff --git a/components/autofill/content/browser/BUILD.gn b/components/autofill/content/browser/BUILD.gn
index 5fa6ea67..edecc7b 100644
--- a/components/autofill/content/browser/BUILD.gn
+++ b/components/autofill/content/browser/BUILD.gn
@@ -31,19 +31,15 @@
     "//components/resources",
     "//components/strings",
     "//components/user_prefs",
-    "//components/webdata/common",
     "//content/public/browser",
     "//content/public/common",
     "//device/geolocation",
-    "//google_apis",
     "//gpu/config",
     "//mojo/common:common_base",
     "//net",
     "//ppapi/features",
     "//services/service_manager/public/cpp",
     "//sql",
-    "//third_party/icu",
-    "//third_party/libphonenumber",
     "//ui/base",
     "//ui/display",
     "//ui/gfx",
@@ -64,7 +60,6 @@
   sources = [
     "content_autofill_driver_unittest.cc",
     "key_press_handler_manager_unittest.cc",
-    "payments/payments_client_unittest.cc",
   ]
 
   deps = [
@@ -77,10 +72,7 @@
     "//content/public/browser",
     "//content/public/common",
     "//content/test:test_support",
-    "//google_apis",
-    "//google_apis:test_support",
     "//mojo/common:common_base",
-    "//net",
     "//net:test_support",
     "//services/service_manager/public/cpp",
     "//testing/gmock",
diff --git a/components/autofill/content/browser/DEPS b/components/autofill/content/browser/DEPS
index 474cd74..302796c 100644
--- a/components/autofill/content/browser/DEPS
+++ b/components/autofill/content/browser/DEPS
@@ -1,13 +1,8 @@
 include_rules = [
-  "+components/webdata/common",
   "+content/public/browser",
   "+crypto/random.h",
   "+device/geolocation",
-  "+google_apis/gaia",
-  "+google_apis/google_api_keys.h",
   "+gpu/config/gpu_info.h",
-  "+sql",
-  "+third_party/libphonenumber",  # For phone number i18n.
   "+third_party/WebKit/public/platform/WebRect.h",
 ]
 
diff --git a/components/autofill/content/browser/payments/OWNERS b/components/autofill/content/browser/payments/OWNERS
deleted file mode 100644
index 6a806bd..0000000
--- a/components/autofill/content/browser/payments/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-mahmadi@chromium.org
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index 6367663c..efd5015 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -357,6 +357,7 @@
     "name_field_unittest.cc",
     "password_generator_unittest.cc",
     "payments/full_card_request_unittest.cc",
+    "payments/payments_client_unittest.cc",
     "payments/payments_service_url_unittest.cc",
     "personal_data_manager_unittest.cc",
     "phone_email_validation_util_unittest.cc",
diff --git a/components/autofill/content/browser/payments/payments_client_unittest.cc b/components/autofill/core/browser/payments/payments_client_unittest.cc
similarity index 98%
rename from components/autofill/content/browser/payments/payments_client_unittest.cc
rename to components/autofill/core/browser/payments/payments_client_unittest.cc
index f7469ad..7dfebb0d 100644
--- a/components/autofill/content/browser/payments/payments_client_unittest.cc
+++ b/components/autofill/core/browser/payments/payments_client_unittest.cc
@@ -8,12 +8,12 @@
 #include "base/command_line.h"
 #include "base/macros.h"
 #include "base/strings/string_piece.h"
+#include "base/test/scoped_task_environment.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/payments/payments_client.h"
 #include "components/autofill/core/common/autofill_switches.h"
-#include "content/public/test/test_browser_thread_bundle.h"
 #include "google_apis/gaia/fake_identity_provider.h"
 #include "google_apis/gaia/fake_oauth2_token_service.h"
 #include "net/url_request/test_url_fetcher_factory.h"
@@ -138,7 +138,7 @@
   std::string real_pan_;
   std::unique_ptr<base::DictionaryValue> legal_message_;
 
-  content::TestBrowserThreadBundle thread_bundle_;
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
   net::TestURLFetcherFactory factory_;
   scoped_refptr<net::TestURLRequestContextGetter> request_context_;
   std::unique_ptr<FakeOAuth2TokenService> token_service_;
@@ -377,5 +377,5 @@
   EXPECT_EQ("", real_pan_);
 }
 
-}  // namespace autofill
 }  // namespace payments
+}  // namespace autofill
diff --git a/components/content_settings/core/browser/content_settings_registry.cc b/components/content_settings/core/browser/content_settings_registry.cc
index 9413166..17218afa 100644
--- a/components/content_settings/core/browser/content_settings_registry.cc
+++ b/components/content_settings/core/browser/content_settings_registry.cc
@@ -317,6 +317,16 @@
            WebsiteSettingsRegistry::DESKTOP |
                WebsiteSettingsRegistry::PLATFORM_ANDROID,
            ContentSettingsInfo::INHERIT_IF_LESS_PERMISSIVE);
+
+  Register(CONTENT_SETTINGS_TYPE_ACCESSIBILITY_EVENTS, "accessibility-events",
+           CONTENT_SETTING_ASK, WebsiteSettingsInfo::UNSYNCABLE,
+           WhitelistedSchemes(),
+           ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK,
+                         CONTENT_SETTING_ASK),
+           WebsiteSettingsInfo::REQUESTING_ORIGIN_AND_TOP_LEVEL_ORIGIN_SCOPE,
+           WebsiteSettingsRegistry::DESKTOP |
+               WebsiteSettingsRegistry::PLATFORM_ANDROID,
+           ContentSettingsInfo::INHERIT_IF_LESS_PERMISSIVE);
 }
 
 void ContentSettingsRegistry::Register(
diff --git a/components/content_settings/core/browser/host_content_settings_map.cc b/components/content_settings/core/browser/host_content_settings_map.cc
index ca96deb..588c900 100644
--- a/components/content_settings/core/browser/host_content_settings_map.cc
+++ b/components/content_settings/core/browser/host_content_settings_map.cc
@@ -755,22 +755,9 @@
 
   while (rule_iterator->HasNext()) {
     const content_settings::Rule& rule = rule_iterator->Next();
-    std::unique_ptr<base::Value> setting_value;
-    // TODO(bauerb): Return rules as a list of values, not content settings.
-    // Handle the case using base::Values for its exceptions and default
-    // setting. Here we assume all the exceptions are granted as
-    // |CONTENT_SETTING_ALLOW|.
-    if (!content_settings::ContentSettingsRegistry::GetInstance()->Get(
-            content_type) &&
-        rule.value.get() &&
-        rule.primary_pattern != ContentSettingsPattern::Wildcard()) {
-      setting_value =
-          content_settings::ContentSettingToValue(CONTENT_SETTING_ALLOW);
-    } else {
-      setting_value = base::MakeUnique<base::Value>(rule.value->Clone());
-    }
     settings->push_back(ContentSettingPatternSource(
-        rule.primary_pattern, rule.secondary_pattern, std::move(setting_value),
+        rule.primary_pattern, rule.secondary_pattern,
+        base::MakeUnique<base::Value>(rule.value->Clone()),
         kProviderNamesSourceMap[provider_type].provider_name, incognito));
   }
 }
diff --git a/components/content_settings/core/common/content_settings.cc b/components/content_settings/core/common/content_settings.cc
index 66b8c4d..de1df544 100644
--- a/components/content_settings/core/common/content_settings.cc
+++ b/components/content_settings/core/common/content_settings.cc
@@ -28,7 +28,7 @@
 // content settings type name instead.
 //
 // The array size must be explicit for the static_asserts below.
-constexpr size_t kNumHistogramValues = 32;
+constexpr size_t kNumHistogramValues = 33;
 constexpr HistogramValue kHistogramValue[kNumHistogramValues] = {
     {CONTENT_SETTINGS_TYPE_COOKIES, 0},
     {CONTENT_SETTINGS_TYPE_IMAGES, 1},
@@ -62,6 +62,7 @@
     {CONTENT_SETTINGS_TYPE_SOUND, 36},
     {CONTENT_SETTINGS_TYPE_CLIENT_HINTS, 37},
     {CONTENT_SETTINGS_TYPE_SENSORS, 38},
+    {CONTENT_SETTINGS_TYPE_ACCESSIBILITY_EVENTS, 39},
 };
 
 }  // namespace
diff --git a/components/content_settings/core/common/content_settings_types.h b/components/content_settings/core/common/content_settings_types.h
index 6e0c1e67..6781f84 100644
--- a/components/content_settings/core/common/content_settings_types.h
+++ b/components/content_settings/core/common/content_settings_types.h
@@ -71,7 +71,7 @@
   // specific origin.
   CONTENT_SETTINGS_TYPE_MEDIA_ENGAGEMENT,
 
-  // Website setting which stores whether or not the site can play audible
+  // Content setting which stores whether or not the site can play audible
   // sound. This will not block playback but instead the user will not hear it.
   CONTENT_SETTINGS_TYPE_SOUND,
 
@@ -92,6 +92,13 @@
   // ContentSettingsType.
   CONTENT_SETTINGS_TYPE_SENSORS,
 
+  // Content setting which stores whether or not the user has granted the site
+  // permission to respond to accessibility events, which can be used to
+  // provide a custom accessibility experience. Requires explicit user consent
+  // because some users may not want sites to know they're using assistive
+  // technology.
+  CONTENT_SETTINGS_TYPE_ACCESSIBILITY_EVENTS,
+
   CONTENT_SETTINGS_NUM_TYPES,
 };
 
diff --git a/components/cronet/android/BUILD.gn b/components/cronet/android/BUILD.gn
index c151817..d33675e 100644
--- a/components/cronet/android/BUILD.gn
+++ b/components/cronet/android/BUILD.gn
@@ -340,6 +340,7 @@
 android_library("cronet_impl_native_java") {
   java_files = [
     "java/src/org/chromium/net/impl/BidirectionalStreamBuilderImpl.java",
+    "java/src/org/chromium/net/impl/BidirectionalStreamNetworkException.java",
     "java/src/org/chromium/net/impl/CronetBidirectionalStream.java",
     "java/src/org/chromium/net/impl/CronetLibraryLoader.java",
     "java/src/org/chromium/net/impl/CronetMetrics.java",
@@ -1255,6 +1256,13 @@
     _source_jar = get_label_info(dep, "target_gen_dir") + "/" + _dep_name +
                   "__compile_java.javac.jar"
     _output_jar = "$_package_dir/" + _dep_name + ".jar"
+
+    # cronet_api.jar is a special case. Its file name is
+    # different from the target name that builds it.
+    if (_output_jar == "$_package_dir/" + "cronet_api_java.jar") {
+      _output_jar = "$_package_dir/" + "cronet_api.jar"
+    }
+
     _copy_dep = ":" + _dep_name + "__compile_java__javac"
     _copy_target_name = "${target_name}_${dep}"
 
diff --git a/components/cronet/android/java/src/org/chromium/net/impl/BidirectionalStreamNetworkException.java b/components/cronet/android/java/src/org/chromium/net/impl/BidirectionalStreamNetworkException.java
new file mode 100644
index 0000000..560179b
--- /dev/null
+++ b/components/cronet/android/java/src/org/chromium/net/impl/BidirectionalStreamNetworkException.java
@@ -0,0 +1,31 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.net.impl;
+
+import org.chromium.base.VisibleForTesting;
+import org.chromium.net.NetError;
+
+/**
+ * Used in {@link CronetBidirectionalStream}. Implements {@link NetworkExceptionImpl}.
+ */
+@VisibleForTesting
+public class BidirectionalStreamNetworkException extends NetworkExceptionImpl {
+    public BidirectionalStreamNetworkException(
+            String message, int errorCode, int cronetInternalErrorCode) {
+        super(message, errorCode, cronetInternalErrorCode);
+    }
+
+    @Override
+    public boolean immediatelyRetryable() {
+        switch (mCronetInternalErrorCode) {
+            case NetError.ERR_SPDY_PING_FAILED:
+            case NetError.ERR_QUIC_HANDSHAKE_FAILED:
+                assert mErrorCode == ERROR_OTHER;
+                return true;
+            default:
+                return super.immediatelyRetryable();
+        }
+    }
+}
diff --git a/components/cronet/android/java/src/org/chromium/net/impl/CronetBidirectionalStream.java b/components/cronet/android/java/src/org/chromium/net/impl/CronetBidirectionalStream.java
index 1ba46ba..92aa537 100644
--- a/components/cronet/android/java/src/org/chromium/net/impl/CronetBidirectionalStream.java
+++ b/components/cronet/android/java/src/org/chromium/net/impl/CronetBidirectionalStream.java
@@ -602,7 +602,7 @@
                     new QuicExceptionImpl("Exception in BidirectionalStream: " + errorString,
                             nativeError, nativeQuicError));
         } else {
-            failWithException(new NetworkExceptionImpl(
+            failWithException(new BidirectionalStreamNetworkException(
                     "Exception in BidirectionalStream: " + errorString, errorCode, nativeError));
         }
     }
diff --git a/components/cronet/android/java/src/org/chromium/net/impl/NetworkExceptionImpl.java b/components/cronet/android/java/src/org/chromium/net/impl/NetworkExceptionImpl.java
index 4c328ab..423e331 100644
--- a/components/cronet/android/java/src/org/chromium/net/impl/NetworkExceptionImpl.java
+++ b/components/cronet/android/java/src/org/chromium/net/impl/NetworkExceptionImpl.java
@@ -11,9 +11,9 @@
  */
 public class NetworkExceptionImpl extends NetworkException {
     // Error code, one of ERROR_*
-    private final int mErrorCode;
+    protected final int mErrorCode;
     // Cronet internal error code.
-    private final int mCronetInternalErrorCode;
+    protected final int mCronetInternalErrorCode;
 
     /**
      * Constructs an exception with a specific error.
@@ -26,6 +26,8 @@
      */
     public NetworkExceptionImpl(String message, int errorCode, int cronetInternalErrorCode) {
         super(message, null);
+        assert errorCode > 0 && errorCode < 12;
+        assert cronetInternalErrorCode < 0;
         mErrorCode = errorCode;
         mCronetInternalErrorCode = cronetInternalErrorCode;
     }
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamTest.java
index 319603d..8509b9e6 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamTest.java
@@ -33,6 +33,7 @@
 import org.chromium.net.MetricsTestUtil.TestRequestFinishedListener;
 import org.chromium.net.TestBidirectionalStreamCallback.FailureType;
 import org.chromium.net.TestBidirectionalStreamCallback.ResponseStep;
+import org.chromium.net.impl.BidirectionalStreamNetworkException;
 import org.chromium.net.impl.CronetBidirectionalStream;
 import org.chromium.net.impl.UrlResponseInfoImpl;
 
@@ -1526,6 +1527,38 @@
         assertNull(mCronetEngine);
     }
 
+    /*
+     * Verifies NetworkException constructed from specific error codes are retryable.
+     */
+    @SmallTest
+    @Feature({"Cronet"})
+    @Test
+    @OnlyRunNativeCronet
+    public void testErrorCodes() throws Exception {
+        // Non-BidirectionalStream specific error codes.
+        checkSpecificErrorCode(NetError.ERR_NAME_NOT_RESOLVED,
+                NetworkException.ERROR_HOSTNAME_NOT_RESOLVED, false);
+        checkSpecificErrorCode(NetError.ERR_INTERNET_DISCONNECTED,
+                NetworkException.ERROR_INTERNET_DISCONNECTED, false);
+        checkSpecificErrorCode(
+                NetError.ERR_NETWORK_CHANGED, NetworkException.ERROR_NETWORK_CHANGED, true);
+        checkSpecificErrorCode(
+                NetError.ERR_CONNECTION_CLOSED, NetworkException.ERROR_CONNECTION_CLOSED, true);
+        checkSpecificErrorCode(
+                NetError.ERR_CONNECTION_REFUSED, NetworkException.ERROR_CONNECTION_REFUSED, false);
+        checkSpecificErrorCode(
+                NetError.ERR_CONNECTION_RESET, NetworkException.ERROR_CONNECTION_RESET, true);
+        checkSpecificErrorCode(NetError.ERR_CONNECTION_TIMED_OUT,
+                NetworkException.ERROR_CONNECTION_TIMED_OUT, true);
+        checkSpecificErrorCode(NetError.ERR_TIMED_OUT, NetworkException.ERROR_TIMED_OUT, true);
+        checkSpecificErrorCode(NetError.ERR_ADDRESS_UNREACHABLE,
+                NetworkException.ERROR_ADDRESS_UNREACHABLE, false);
+        // BidirectionalStream specific retryable error codes.
+        checkSpecificErrorCode(NetError.ERR_SPDY_PING_FAILED, NetworkException.ERROR_OTHER, true);
+        checkSpecificErrorCode(
+                NetError.ERR_QUIC_HANDSHAKE_FAILED, NetworkException.ERROR_OTHER, true);
+    }
+
     // Returns the contents of byteBuffer, from its position() to its limit(),
     // as a String. Does not modify byteBuffer's position().
     private static String bufferContentsToString(ByteBuffer byteBuffer, int start, int end) {
@@ -1537,4 +1570,13 @@
         duplicate.get(contents);
         return new String(contents);
     }
+
+    private static void checkSpecificErrorCode(
+            int netError, int errorCode, boolean immediatelyRetryable) throws Exception {
+        NetworkException exception =
+                new BidirectionalStreamNetworkException("", errorCode, netError);
+        assertEquals(immediatelyRetryable, exception.immediatelyRetryable());
+        assertEquals(netError, exception.getCronetInternalErrorCode());
+        assertEquals(errorCode, exception.getErrorCode());
+    }
 }
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestTest.java
index c6eb2cc8..b649075b 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestTest.java
@@ -2076,6 +2076,8 @@
         assertNotNull(callback.mError);
         assertEquals(netError, ((NetworkException) callback.mError).getCronetInternalErrorCode());
         assertEquals(errorCode, ((NetworkException) callback.mError).getErrorCode());
+        assertEquals(
+                immediatelyRetryable, ((NetworkException) callback.mError).immediatelyRetryable());
         assertContains(
                 "Exception in CronetUrlRequest: net::ERR_" + name, callback.mError.getMessage());
         assertEquals(0, callback.mRedirectCount);
diff --git a/components/cronet/stale_host_resolver.cc b/components/cronet/stale_host_resolver.cc
index 2d4c077..cc974a8 100644
--- a/components/cronet/stale_host_resolver.cc
+++ b/components/cronet/stale_host_resolver.cc
@@ -46,6 +46,12 @@
                             MAX_REQUEST_OUTCOME);
 }
 
+void RecordCacheSizes(size_t restored, size_t current) {
+  UMA_HISTOGRAM_COUNTS_1000("DNS.StaleHostResolver.RestoreSizeOnCacheMiss",
+                            restored);
+  UMA_HISTOGRAM_COUNTS_1000("DNS.StaleHostResolver.SizeOnCacheMiss", current);
+}
+
 void RecordAddressListDelta(net::AddressListDeltaType delta) {
   UMA_HISTOGRAM_ENUMERATION("DNS.StaleHostResolver.StaleAddressListDelta",
                             delta, net::MAX_DELTA_TYPE);
@@ -175,6 +181,13 @@
   // The underlying network request, so the priority can be changed.
   std::unique_ptr<net::HostResolver::Request> network_request_;
 
+  // Statistics used in histograms:
+  // Number of HostCache entries that were restored from prefs, recorded at the
+  // time the cache was checked.
+  size_t restore_size_;
+  // Current HostCache size at the time the cache was checked.
+  size_t current_size_;
+
   // Handle that caller can use to cancel the request before it returns.
   // Owned by the caller; cleared via |OnHandleDestroyed()| when destroyed.
   Handle* handle_;
@@ -184,6 +197,8 @@
     : result_addresses_(nullptr),
       returning_result_(false),
       stale_error_(net::ERR_DNS_CACHE_MISS),
+      restore_size_(0),
+      current_size_(0),
       handle_(nullptr) {}
 
 StaleHostResolver::RequestImpl::~RequestImpl() {}
@@ -205,6 +220,8 @@
   DCHECK(!usable_callback.is_null());
 
   result_addresses_ = addresses;
+  restore_size_ = resolver->LastRestoredCacheSize();
+  current_size_ = resolver->CacheSize();
 
   net::AddressList cache_addresses;
   net::HostCache::EntryStaleness stale_info;
@@ -329,12 +346,14 @@
         FindAddressListDeltaType(stale_addresses_, network_addresses_));
   }
 
-  if (returned_stale_data)
+  if (returned_stale_data) {
     RecordRequestOutcome(STALE_BEFORE_NETWORK);
-  else if (have_stale_data())
+  } else if (have_stale_data()) {
     RecordRequestOutcome(NETWORK_WITH_STALE);
-  else
+    RecordCacheSizes(restore_size_, current_size_);
+  } else {
     RecordRequestOutcome(NETWORK_WITHOUT_STALE);
+  }
 }
 
 void StaleHostResolver::RequestImpl::RecordCanceledRequest() {
diff --git a/components/cryptauth/cryptauth_test_util.cc b/components/cryptauth/cryptauth_test_util.cc
index 60b31f8..fa91e7e 100644
--- a/components/cryptauth/cryptauth_test_util.cc
+++ b/components/cryptauth/cryptauth_test_util.cc
@@ -12,6 +12,7 @@
 const char kTestRemoteDevicePublicKey[] = "public key";
 const char kTestRemoteDeviceBluetoothAddress[] = "AA:BB:CC:DD:EE:FF";
 const char kTestRemoteDevicePSK[] = "remote device psk";
-const char kTestRemoteDeviceSignInChallenge[] = "sign-in challenge";
+const bool kTestRemoteDeviceUnlockKey = true;
+const bool kTestRemoteDeviceSupportsMobileHotspot = true;
 
 }  // namespace cryptauth
diff --git a/components/cryptauth/cryptauth_test_util.h b/components/cryptauth/cryptauth_test_util.h
index 4c43b81..b576fc0 100644
--- a/components/cryptauth/cryptauth_test_util.h
+++ b/components/cryptauth/cryptauth_test_util.h
@@ -15,14 +15,16 @@
 extern const char kTestRemoteDevicePublicKey[];
 extern const char kTestRemoteDeviceBluetoothAddress[];
 extern const char kTestRemoteDevicePSK[];
-extern const char kTestRemoteDeviceSignInChallenge[];
+extern const bool kTestRemoteDeviceUnlockKey;
+extern const bool kTestRemoteDeviceSupportsMobileHotspot;
 
 // Returns a BLE RemoteDevice used for tests.
 inline RemoteDevice CreateLERemoteDeviceForTest() {
   return RemoteDevice(kTestRemoteDeviceUserId, kTestRemoteDeviceName,
                       kTestRemoteDevicePublicKey,
                       kTestRemoteDeviceBluetoothAddress, kTestRemoteDevicePSK,
-                      kTestRemoteDeviceSignInChallenge);
+                      kTestRemoteDeviceUnlockKey,
+                      kTestRemoteDeviceSupportsMobileHotspot);
 }
 
 // Returns a classic Bluetooth RemoteDevice used for tests.
@@ -30,7 +32,8 @@
   return RemoteDevice(kTestRemoteDeviceUserId, kTestRemoteDeviceName,
                       kTestRemoteDevicePublicKey,
                       kTestRemoteDeviceBluetoothAddress, kTestRemoteDevicePSK,
-                      kTestRemoteDeviceSignInChallenge);
+                      kTestRemoteDeviceUnlockKey,
+                      kTestRemoteDeviceSupportsMobileHotspot);
 }
 
 }  // namespace cryptauth
diff --git a/components/cryptauth/remote_device.cc b/components/cryptauth/remote_device.cc
index b9556956e..e5ef475 100644
--- a/components/cryptauth/remote_device.cc
+++ b/components/cryptauth/remote_device.cc
@@ -32,20 +32,23 @@
 
 }  // namespace
 
-RemoteDevice::RemoteDevice() {}
+RemoteDevice::RemoteDevice()
+    : unlock_key(false), supports_mobile_hotspot(false) {}
 
 RemoteDevice::RemoteDevice(const std::string& user_id,
                            const std::string& name,
                            const std::string& public_key,
                            const std::string& bluetooth_address,
                            const std::string& persistent_symmetric_key,
-                           std::string sign_in_challenge)
+                           bool unlock_key,
+                           bool supports_mobile_hotspot)
     : user_id(user_id),
       name(name),
       public_key(public_key),
       bluetooth_address(bluetooth_address),
       persistent_symmetric_key(persistent_symmetric_key),
-      sign_in_challenge(sign_in_challenge) {}
+      unlock_key(unlock_key),
+      supports_mobile_hotspot(supports_mobile_hotspot) {}
 
 RemoteDevice::RemoteDevice(const RemoteDevice& other) = default;
 
@@ -82,7 +85,9 @@
          public_key == other.public_key &&
          bluetooth_address == other.bluetooth_address &&
          persistent_symmetric_key == other.persistent_symmetric_key &&
-         sign_in_challenge == other.sign_in_challenge && are_beacon_seeds_equal;
+         unlock_key == other.unlock_key &&
+         supports_mobile_hotspot == other.supports_mobile_hotspot &&
+         are_beacon_seeds_equal;
 }
 
 bool RemoteDevice::operator<(const RemoteDevice& other) const {
diff --git a/components/cryptauth/remote_device.h b/components/cryptauth/remote_device.h
index 7662b1a..1f2953d 100644
--- a/components/cryptauth/remote_device.h
+++ b/components/cryptauth/remote_device.h
@@ -19,7 +19,8 @@
   std::string public_key;
   std::string bluetooth_address;
   std::string persistent_symmetric_key;
-  std::string sign_in_challenge;
+  bool unlock_key;
+  bool supports_mobile_hotspot;
 
   // Note: To save space, the BeaconSeeds may not necessarily be included in
   // this object.
@@ -32,7 +33,8 @@
                const std::string& public_key,
                const std::string& bluetooth_address,
                const std::string& persistent_symmetric_key,
-               std::string sign_in_challenge);
+               bool unlock_key,
+               bool supports_mobile_hotspot);
   RemoteDevice(const RemoteDevice& other);
   ~RemoteDevice();
 
diff --git a/components/cryptauth/remote_device_loader.cc b/components/cryptauth/remote_device_loader.cc
index 705a1262d..398bd78 100644
--- a/components/cryptauth/remote_device_loader.cc
+++ b/components/cryptauth/remote_device_loader.cc
@@ -106,7 +106,8 @@
 
   cryptauth::RemoteDevice remote_device(
       user_id_, device.friendly_device_name(), device.public_key(),
-      device.bluetooth_address(), psk, std::string());
+      device.bluetooth_address(), psk, device.unlock_key(),
+      device.mobile_hotspot_supported());
 
   if (should_load_beacon_seeds_) {
     std::vector<BeaconSeed> beacon_seeds;
diff --git a/components/cryptauth/remote_device_loader_unittest.cc b/components/cryptauth/remote_device_loader_unittest.cc
index 3f538d38..3b66403 100644
--- a/components/cryptauth/remote_device_loader_unittest.cc
+++ b/components/cryptauth/remote_device_loader_unittest.cc
@@ -153,6 +153,37 @@
                remote_device_without_beacon_seed);
 }
 
+TEST_F(CryptAuthRemoteDeviceLoaderTest, BooleanAttributes) {
+  cryptauth::ExternalDeviceInfo first = CreateDeviceInfo("0");
+  first.set_unlock_key(true);
+  first.set_mobile_hotspot_supported(true);
+
+  cryptauth::ExternalDeviceInfo second = CreateDeviceInfo("1");
+  second.set_unlock_key(false);
+  second.set_mobile_hotspot_supported(false);
+
+  std::vector<cryptauth::ExternalDeviceInfo> device_infos{first, second};
+
+  RemoteDeviceLoader loader(device_infos, user_private_key_, kUserId,
+                            std::move(secure_message_delegate_));
+
+  std::vector<cryptauth::RemoteDevice> result;
+  EXPECT_CALL(*this, LoadCompleted());
+  loader.Load(
+      false, base::Bind(&CryptAuthRemoteDeviceLoaderTest::OnRemoteDevicesLoaded,
+                        base::Unretained(this)));
+
+  EXPECT_EQ(2u, remote_devices_.size());
+
+  EXPECT_FALSE(remote_devices_[0].persistent_symmetric_key.empty());
+  EXPECT_TRUE(remote_devices_[0].unlock_key);
+  EXPECT_TRUE(remote_devices_[0].supports_mobile_hotspot);
+
+  EXPECT_FALSE(remote_devices_[1].persistent_symmetric_key.empty());
+  EXPECT_FALSE(remote_devices_[1].unlock_key);
+  EXPECT_FALSE(remote_devices_[1].supports_mobile_hotspot);
+}
+
 TEST_F(CryptAuthRemoteDeviceLoaderTest, LoadOneDeviceWithAddress) {
   std::vector<cryptauth::ExternalDeviceInfo> device_infos(1,
                                                          CreateDeviceInfo("0"));
diff --git a/components/exo/pointer.cc b/components/exo/pointer.cc
index d607a72..c74dfd07 100644
--- a/components/exo/pointer.cc
+++ b/components/exo/pointer.cc
@@ -123,8 +123,10 @@
     cursor_changed = true;
   }
 
-  if (hotspot != hotspot_)
+  if (hotspot != cursor_hotspot_) {
+    hotspot_ = hotspot;
     cursor_changed = true;
+  }
 
   // Early out if cursor did not change.
   if (!cursor_changed) {
@@ -378,7 +380,7 @@
   } else {
     DCHECK(result->HasBitmap());
     cursor_bitmap_ = *result->TakeBitmap();
-    hotspot_ = hotspot;
+    cursor_hotspot_ = hotspot;
   }
 
   UpdateCursor();
@@ -391,7 +393,8 @@
     cursor_ = ui::CursorType::kNone;
   } else {
     SkBitmap bitmap = cursor_bitmap_;
-    gfx::Point hotspot = gfx::ScaleToFlooredPoint(hotspot_, capture_ratio_);
+    gfx::Point hotspot =
+        gfx::ScaleToFlooredPoint(cursor_hotspot_, capture_ratio_);
 
     auto* helper = WMHelper::GetInstance();
     const display::Display& display = helper->GetCursorDisplay();
diff --git a/components/exo/pointer.h b/components/exo/pointer.h
index 98140bc..21d98c7 100644
--- a/components/exo/pointer.h
+++ b/components/exo/pointer.h
@@ -110,6 +110,9 @@
   // The current cursor.
   ui::Cursor cursor_;
 
+  // Hotspot to use with latest cursor snapshot.
+  gfx::Point cursor_hotspot_;
+
   // Scale at which cursor snapshot is captured.
   float capture_scale_;
 
diff --git a/components/exo/shell_surface.cc b/components/exo/shell_surface.cc
index f58d54f..b3133051a 100644
--- a/components/exo/shell_surface.cc
+++ b/components/exo/shell_surface.cc
@@ -1009,6 +1009,7 @@
   if (widget_) {
     UpdateWidgetBounds();
     UpdateShadow();
+    UpdateBackdrop();
   }
 
   if (old_type != new_type && !state_changed_callback_.is_null())
@@ -1709,17 +1710,9 @@
 
   shadow_content_bounds_changed_ = false;
 
-  aura::Window* window = widget_->GetNativeWindow();
+  UpdateBackdrop();
 
-  // Enable the black backdrop layer behind the window if the window
-  // is in immersive fullscreen, maximized, yet the window can control
-  // the bounds of the window in fullscreen/tablet mode (thus the
-  // background can be visible).
-  bool enable_backdrop =
-      (widget_->IsFullscreen() || widget_->IsMaximized()) &&
-      ash::wm::GetWindowState(window)->allow_set_bounds_direct();
-  if (window->GetProperty(aura::client::kHasBackdrop) != enable_backdrop)
-    window->SetProperty(aura::client::kHasBackdrop, enable_backdrop);
+  aura::Window* window = widget_->GetNativeWindow();
 
   if (!shadow_enabled_) {
     wm::SetShadowElevation(window, wm::ShadowElevation::NONE);
@@ -1817,6 +1810,19 @@
   }
 }
 
+void ShellSurface::UpdateBackdrop() {
+  aura::Window* window = widget_->GetNativeWindow();
+  // Enable the black backdrop layer behind the window if the window
+  // is in immersive fullscreen, maximized, yet the window can control
+  // the bounds of the window in fullscreen/tablet mode (thus the
+  // background can be visible).
+  bool enable_backdrop =
+      (widget_->IsFullscreen() || widget_->IsMaximized()) &&
+      ash::wm::GetWindowState(window)->allow_set_bounds_direct();
+  if (window->GetProperty(aura::client::kHasBackdrop) != enable_backdrop)
+    window->SetProperty(aura::client::kHasBackdrop, enable_backdrop);
+}
+
 gfx::Point ShellSurface::GetMouseLocation() const {
   aura::Window* const root_window = widget_->GetNativeWindow()->GetRootWindow();
   gfx::Point location =
diff --git a/components/exo/shell_surface.h b/components/exo/shell_surface.h
index ebfb0de6..ef75cab 100644
--- a/components/exo/shell_surface.h
+++ b/components/exo/shell_surface.h
@@ -354,6 +354,10 @@
   // Applies |system_modal_| to |widget_|.
   void UpdateSystemModal();
 
+  // Updates the backdrop state of the shell surface based on the
+  // bounds mode and window state.
+  void UpdateBackdrop();
+
   // In the coordinate system of the parent root window.
   gfx::Point GetMouseLocation() const;
 
diff --git a/components/exo/shell_surface_unittest.cc b/components/exo/shell_surface_unittest.cc
index 04858f14..ebbbe322 100644
--- a/components/exo/shell_surface_unittest.cc
+++ b/components/exo/shell_surface_unittest.cc
@@ -65,6 +65,38 @@
          type == ash::mojom::WindowPinType::TRUSTED_PINNED;
 }
 
+class ShellSurfaceBoundsModeTest
+    : public ShellSurfaceTest,
+      public testing::WithParamInterface<ShellSurface::BoundsMode> {
+ public:
+  ShellSurfaceBoundsModeTest() {}
+  ~ShellSurfaceBoundsModeTest() override {}
+
+  bool IsClientBoundsMode() const {
+    return GetParam() == ShellSurface::BoundsMode::CLIENT;
+  }
+
+  bool HasBackdrop() {
+    ash::WorkspaceController* wc =
+        ash::ShellTestApi(ash::Shell::Get()).workspace_controller();
+    return !!ash::WorkspaceControllerTestApi(wc).GetBackdropWindow();
+  }
+
+  std::unique_ptr<ShellSurface> CreateDefaultShellSurface(Surface* surface) {
+    return base::MakeUnique<ShellSurface>(surface, nullptr, GetParam(),
+                                          gfx::Point(), true, false,
+                                          ash::kShellWindowId_DefaultContainer);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ShellSurfaceBoundsModeTest);
+};
+
+INSTANTIATE_TEST_CASE_P(,
+                        ShellSurfaceBoundsModeTest,
+                        testing::Values(ShellSurface::BoundsMode::CLIENT,
+                                        ShellSurface::BoundsMode::SHELL));
+
 TEST_F(ShellSurfaceTest, AcknowledgeConfigure) {
   gfx::Size buffer_size(32, 32);
   std::unique_ptr<Buffer> buffer(
@@ -124,18 +156,38 @@
       wm::GetTransientParent(shell_surface->GetWidget()->GetNativeWindow()));
 }
 
-TEST_F(ShellSurfaceTest, Maximize) {
+TEST_P(ShellSurfaceBoundsModeTest, Maximize) {
   gfx::Size buffer_size(256, 256);
   std::unique_ptr<Buffer> buffer(
       new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
   std::unique_ptr<Surface> surface(new Surface);
-  std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
+  std::unique_ptr<ShellSurface> shell_surface(
+      CreateDefaultShellSurface(surface.get()));
 
   surface->Attach(buffer.get());
-  shell_surface->Maximize();
   surface->Commit();
-  EXPECT_EQ(CurrentContext()->bounds().width(),
-            shell_surface->GetWidget()->GetWindowBoundsInScreen().width());
+  EXPECT_FALSE(HasBackdrop());
+  shell_surface->Maximize();
+  EXPECT_EQ(IsClientBoundsMode(), HasBackdrop());
+  surface->Commit();
+  EXPECT_EQ(IsClientBoundsMode(), HasBackdrop());
+  if (!IsClientBoundsMode()) {
+    EXPECT_EQ(CurrentContext()->bounds().width(),
+              shell_surface->GetWidget()->GetWindowBoundsInScreen().width());
+  }
+  EXPECT_TRUE(shell_surface->GetWidget()->IsMaximized());
+
+  // Toggle maximize.
+  ash::wm::WMEvent maximize_event(ash::wm::WM_EVENT_TOGGLE_MAXIMIZE);
+  aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
+
+  ash::wm::GetWindowState(window)->OnWMEvent(&maximize_event);
+  EXPECT_FALSE(shell_surface->GetWidget()->IsMaximized());
+  EXPECT_FALSE(HasBackdrop());
+
+  ash::wm::GetWindowState(window)->OnWMEvent(&maximize_event);
+  EXPECT_TRUE(shell_surface->GetWidget()->IsMaximized());
+  EXPECT_EQ(IsClientBoundsMode(), HasBackdrop());
 }
 
 TEST_F(ShellSurfaceTest, Minimize) {
@@ -161,34 +213,51 @@
   EXPECT_TRUE(shell_surface->GetWidget()->IsMinimized());
 }
 
-TEST_F(ShellSurfaceTest, Restore) {
+TEST_P(ShellSurfaceBoundsModeTest, Restore) {
   gfx::Size buffer_size(256, 256);
   std::unique_ptr<Buffer> buffer(
       new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
   std::unique_ptr<Surface> surface(new Surface);
-  std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
+  std::unique_ptr<ShellSurface> shell_surface(
+      CreateDefaultShellSurface(surface.get()));
 
   surface->Attach(buffer.get());
   surface->Commit();
+  EXPECT_FALSE(HasBackdrop());
   // Note: Remove contents to avoid issues with maximize animations in tests.
   shell_surface->Maximize();
+  EXPECT_EQ(IsClientBoundsMode(), HasBackdrop());
   shell_surface->Restore();
-  EXPECT_EQ(
-      buffer_size.ToString(),
-      shell_surface->GetWidget()->GetWindowBoundsInScreen().size().ToString());
+  EXPECT_FALSE(HasBackdrop());
+  if (!IsClientBoundsMode()) {
+    EXPECT_EQ(buffer_size.ToString(), shell_surface->GetWidget()
+                                          ->GetWindowBoundsInScreen()
+                                          .size()
+                                          .ToString());
+  }
 }
 
-TEST_F(ShellSurfaceTest, SetFullscreen) {
+TEST_P(ShellSurfaceBoundsModeTest, SetFullscreen) {
   gfx::Size buffer_size(256, 256);
   std::unique_ptr<Buffer> buffer(
       new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
   std::unique_ptr<Surface> surface(new Surface);
-  std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
+  std::unique_ptr<ShellSurface> shell_surface(
+      CreateDefaultShellSurface(surface.get()));
 
   shell_surface->SetFullscreen(true);
   surface->Attach(buffer.get());
   surface->Commit();
-  EXPECT_EQ(CurrentContext()->bounds().ToString(),
+  EXPECT_EQ(IsClientBoundsMode(), HasBackdrop());
+  if (!IsClientBoundsMode()) {
+    EXPECT_EQ(CurrentContext()->bounds().ToString(),
+              shell_surface->GetWidget()->GetWindowBoundsInScreen().ToString());
+  }
+
+  shell_surface->SetFullscreen(false);
+  surface->Commit();
+  EXPECT_FALSE(HasBackdrop());
+  EXPECT_NE(CurrentContext()->bounds().ToString(),
             shell_surface->GetWidget()->GetWindowBoundsInScreen().ToString());
 }
 
@@ -884,22 +953,29 @@
   EXPECT_EQ(gfx::Rect(10, 10, 100, 100), shadow->layer()->parent()->bounds());
 }
 
-TEST_F(ShellSurfaceTest, ToggleFullscreen) {
+TEST_P(ShellSurfaceBoundsModeTest, ToggleFullscreen) {
   gfx::Size buffer_size(256, 256);
   std::unique_ptr<Buffer> buffer(
       new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
   std::unique_ptr<Surface> surface(new Surface);
-  std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
+  std::unique_ptr<ShellSurface> shell_surface(
+      CreateDefaultShellSurface(surface.get()));
 
   surface->Attach(buffer.get());
   surface->Commit();
-  EXPECT_EQ(
-      buffer_size.ToString(),
-      shell_surface->GetWidget()->GetWindowBoundsInScreen().size().ToString());
-
+  EXPECT_FALSE(HasBackdrop());
+  if (!IsClientBoundsMode()) {
+    EXPECT_EQ(buffer_size.ToString(), shell_surface->GetWidget()
+                                          ->GetWindowBoundsInScreen()
+                                          .size()
+                                          .ToString());
+  }
   shell_surface->Maximize();
-  EXPECT_EQ(CurrentContext()->bounds().width(),
-            shell_surface->GetWidget()->GetWindowBoundsInScreen().width());
+  EXPECT_EQ(IsClientBoundsMode(), HasBackdrop());
+  if (!IsClientBoundsMode()) {
+    EXPECT_EQ(CurrentContext()->bounds().width(),
+              shell_surface->GetWidget()->GetWindowBoundsInScreen().width());
+  }
 
   ash::wm::WMEvent event(ash::wm::WM_EVENT_TOGGLE_FULLSCREEN);
   aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
@@ -907,68 +983,21 @@
   // Enter fullscreen mode.
   ash::wm::GetWindowState(window)->OnWMEvent(&event);
 
-  EXPECT_EQ(CurrentContext()->bounds().ToString(),
-            shell_surface->GetWidget()->GetWindowBoundsInScreen().ToString());
+  EXPECT_EQ(IsClientBoundsMode(), HasBackdrop());
+  if (!IsClientBoundsMode()) {
+    EXPECT_EQ(CurrentContext()->bounds().ToString(),
+              shell_surface->GetWidget()->GetWindowBoundsInScreen().ToString());
+  }
 
   // Leave fullscreen mode.
   ash::wm::GetWindowState(window)->OnWMEvent(&event);
+  EXPECT_EQ(IsClientBoundsMode(), HasBackdrop());
 
   // Check that shell surface is maximized.
-  EXPECT_EQ(CurrentContext()->bounds().width(),
-            shell_surface->GetWidget()->GetWindowBoundsInScreen().width());
-}
-
-TEST_F(ShellSurfaceTest, MaximizedAndImmersiveFullscreenBackdrop) {
-  ash::WorkspaceController* wc =
-      ash::ShellTestApi(ash::Shell::Get()).workspace_controller();
-  ash::WorkspaceControllerTestApi test_helper(wc);
-
-  const gfx::Size display_size =
-      display::Screen::GetScreen()->GetPrimaryDisplay().size();
-  const gfx::Size buffer_size(display_size);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(
-      surface.get(), nullptr, ShellSurface::BoundsMode::CLIENT, gfx::Point(),
-      true, false, ash::kShellWindowId_DefaultContainer));
-
-  surface->Attach(buffer.get());
-
-  gfx::Rect shadow_bounds(10, 10, 100, 100);
-  shell_surface->SetGeometry(shadow_bounds);
-  shell_surface->SetRectangularSurfaceShadow(shadow_bounds);
-  surface->Commit();
-  EXPECT_EQ(shadow_bounds,
-            shell_surface->GetWidget()->GetWindowBoundsInScreen());
-  ASSERT_EQ(shadow_bounds,
-            shell_surface->shadow_underlay()->GetBoundsInScreen());
-  EXPECT_EQ(display::Screen::GetScreen()->GetPrimaryDisplay().size(),
-            shell_surface->surface_for_testing()->window()->bounds().size());
-
-  EXPECT_FALSE(test_helper.GetBackdropWindow());
-
-  ash::wm::WMEvent fullscreen_event(ash::wm::WM_EVENT_TOGGLE_FULLSCREEN);
-  aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
-
-  // Enter immersive fullscreen mode. Shadow underlay is fullscreen.
-  ash::wm::GetWindowState(window)->OnWMEvent(&fullscreen_event);
-
-  EXPECT_TRUE(test_helper.GetBackdropWindow());
-
-  // Leave fullscreen mode. Shadow underlay is restored.
-  ash::wm::GetWindowState(window)->OnWMEvent(&fullscreen_event);
-  EXPECT_FALSE(test_helper.GetBackdropWindow());
-
-  ash::wm::WMEvent maximize_event(ash::wm::WM_EVENT_TOGGLE_MAXIMIZE);
-
-  // Enter tablet mode.
-  ash::wm::GetWindowState(window)->OnWMEvent(&maximize_event);
-  EXPECT_TRUE(test_helper.GetBackdropWindow());
-
-  // Leave tablet mode.
-  ash::wm::GetWindowState(window)->OnWMEvent(&maximize_event);
-  EXPECT_FALSE(test_helper.GetBackdropWindow());
+  if (!IsClientBoundsMode()) {
+    EXPECT_EQ(CurrentContext()->bounds().width(),
+              shell_surface->GetWidget()->GetWindowBoundsInScreen().width());
+  }
 }
 
 // Make sure that a surface shell started in maximize creates deprecated
diff --git a/components/leveldb/env_mojo.cc b/components/leveldb/env_mojo.cc
index 00bc573..0f17d71 100644
--- a/components/leveldb/env_mojo.cc
+++ b/components/leveldb/env_mojo.cc
@@ -46,11 +46,9 @@
   snprintf(buf, sizeof(buf), "%s (MojoFSError: %d::%s)", err_str.c_str(),
            method, MethodIDToString(method));
 
-  if (error == FileError::NOT_FOUND) {
-    return Status::NotFound(filename, buf);
-  } else {
-    return Status::IOError(filename, buf);
-  }
+  // TOOD(crbug.com/760362): Map FileError::NOT_FOUND to Status::NotFound, after
+  //                         fixing LevelDB to handle the NotFound correctly.
+  return Status::IOError(filename, buf);
 }
 
 class MojoFileLock : public FileLock {
diff --git a/components/metrics/proto/ukm/source.proto b/components/metrics/proto/ukm/source.proto
index d4a00605..7b10ae2 100644
--- a/components/metrics/proto/ukm/source.proto
+++ b/components/metrics/proto/ukm/source.proto
@@ -9,7 +9,7 @@
 option optimize_for = LITE_RUNTIME;
 
 // Source contains data related to a top-level navigation.
-// Next tag: 7
+// Next tag: 8
 message Source {
   // An identifier for the source. This should be unique within a session.
   optional int64 id = 1;
@@ -27,6 +27,9 @@
   // discovered by Google's crawler, it should not be recorded.
   optional string initial_url = 6;
 
+  // Flag indicating if the metric was collected while inside a "custom tab".
+  optional bool is_custom_tab = 7;
+
   // Timestamp of navigation to this Source, as seen by the client. Time of
   // events related to this Source will generally be relative to this timestamp.
   optional int64 navigation_time_msec = 3;
diff --git a/components/nacl/loader/nacl_listener.cc b/components/nacl/loader/nacl_listener.cc
index fa2c47ad..f6896364 100644
--- a/components/nacl/loader/nacl_listener.cc
+++ b/components/nacl/loader/nacl_listener.cc
@@ -45,6 +45,10 @@
 #include "content/public/common/common_sandbox_support_linux.h"
 #endif
 
+#if defined(OS_POSIX)
+#include "base/posix/eintr_wrapper.h"
+#endif
+
 #if defined(OS_WIN)
 #include <io.h>
 
@@ -285,7 +289,7 @@
 void NaClListener::OnStart(const nacl::NaClStartParams& params) {
   is_started_ = true;
 #if defined(OS_LINUX) || defined(OS_MACOSX)
-  int urandom_fd = dup(base::GetUrandomFD());
+  int urandom_fd = HANDLE_EINTR(dup(base::GetUrandomFD()));
   if (urandom_fd < 0) {
     LOG(FATAL) << "Failed to dup() the urandom FD";
   }
diff --git a/components/ntp_tiles/webui/resources/ntp_tiles_internals.html b/components/ntp_tiles/webui/resources/ntp_tiles_internals.html
index 628b47a..8e922ea 100644
--- a/components/ntp_tiles/webui/resources/ntp_tiles_internals.html
+++ b/components/ntp_tiles/webui/resources/ntp_tiles_internals.html
@@ -46,7 +46,7 @@
       <tbody jsselect="suggestionsService">
         <tr jsdisplay="$this">
           <td class="detail">
-            <input id="suggestions-fetch" type="submit" value="Fetch"></input>
+            <input id="suggestions-fetch" type="submit" value="Fetch">
           </td>
           <td class="value" jscontent="status"></td>
         </tr>
@@ -77,7 +77,7 @@
         </tr>
         <tr jsdisplay="$this">
           <td class="detail">
-            <input id="popular-view-json" type="submit", value="View JSON"></input>
+            <input id="popular-view-json" type="submit", value="View JSON">
           </td>
           <td class="value"><pre id="popular-json-value" jscontent="json"></pre></td>
         </tr>
@@ -96,7 +96,7 @@
           <td class="value" jsdisplay="!$this">no</td>
         </tr>
         <tr jsskip="true">
-          <th colspan="2"><input id="submit-update" type="submit" value="Update"></input></th>
+          <th colspan="2"><input id="submit-update" type="submit" value="Update"></th>
         </tr>
       </tbody>
     </table>
diff --git a/components/offline_pages/core/BUILD.gn b/components/offline_pages/core/BUILD.gn
index f851b6f9..eb23f53 100644
--- a/components/offline_pages/core/BUILD.gn
+++ b/components/offline_pages/core/BUILD.gn
@@ -36,6 +36,10 @@
     "offline_page_storage_manager.cc",
     "offline_page_storage_manager.h",
     "offline_page_types.h",
+    "offline_pages_ukm_reporter.cc",
+    "offline_pages_ukm_reporter.h",
+    "offline_pages_ukm_reporter_stub.cc",
+    "offline_pages_ukm_reporter_stub.h",
     "offline_store_types.h",
     "offline_time_utils.cc",
     "offline_time_utils.h",
@@ -52,6 +56,8 @@
     "//base",
     "//components/keyed_service/core",
     "//net",
+    "//services/metrics/public/cpp:metrics_cpp",
+    "//services/metrics/public/cpp:ukm_builders",
     "//sql:sql",
     "//url",
   ]
@@ -103,6 +109,7 @@
     "offline_page_model_impl_unittest.cc",
     "offline_page_model_query_unittest.cc",
     "offline_page_storage_manager_unittest.cc",
+    "offline_pages_ukm_reporter_unittest.cc",
     "snapshot_controller_unittest.cc",
     "task_queue_unittest.cc",
     "task_unittest.cc",
@@ -117,6 +124,8 @@
     "renovations:unit_tests",
     "//base",
     "//base/test:test_support",
+    "//components/ukm:test_support",
+    "//services/metrics/public/cpp:ukm_builders",
     "//sql:sql",
     "//testing/gtest",
     "//url",
diff --git a/components/offline_pages/core/DEPS b/components/offline_pages/core/DEPS
index 5d8bc16..852e57ee 100644
--- a/components/offline_pages/core/DEPS
+++ b/components/offline_pages/core/DEPS
@@ -1,4 +1,6 @@
 include_rules = [
   "+components/keyed_service",
+  "+components/ukm",
+  "+services/metrics/public/cpp",
   "+sql",
 ]
diff --git a/components/offline_pages/core/background/BUILD.gn b/components/offline_pages/core/background/BUILD.gn
index 083e7a9..17f84eb 100644
--- a/components/offline_pages/core/background/BUILD.gn
+++ b/components/offline_pages/core/background/BUILD.gn
@@ -87,6 +87,7 @@
   deps = [
     ":background_offliner",
     "//base",
+    "//components/offline_pages/core",
     "//net",
   ]
 }
diff --git a/components/offline_pages/core/background/request_coordinator.cc b/components/offline_pages/core/background/request_coordinator.cc
index 099a91f..1772877 100644
--- a/components/offline_pages/core/background/request_coordinator.cc
+++ b/components/offline_pages/core/background/request_coordinator.cc
@@ -21,6 +21,7 @@
 #include "components/offline_pages/core/offline_page_feature.h"
 #include "components/offline_pages/core/offline_page_item.h"
 #include "components/offline_pages/core/offline_page_model.h"
+#include "components/offline_pages/core/offline_pages_ukm_reporter.h"
 
 namespace offline_pages {
 
@@ -216,7 +217,8 @@
     std::unique_ptr<RequestQueue> queue,
     std::unique_ptr<Scheduler> scheduler,
     net::NetworkQualityEstimator::NetworkQualityProvider*
-        network_quality_estimator)
+        network_quality_estimator,
+    std::unique_ptr<OfflinePagesUkmReporter> ukm_reporter)
     : is_low_end_device_(base::SysInfo::IsLowEndDevice()),
       state_(RequestCoordinatorState::IDLE),
       processing_state_(ProcessingWindowState::STOPPED),
@@ -227,6 +229,7 @@
       scheduler_(std::move(scheduler)),
       policy_controller_(new ClientPolicyController()),
       network_quality_estimator_(network_quality_estimator),
+      ukm_reporter_(std::move(ukm_reporter)),
       network_quality_at_request_start_(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN),
       active_request_id_(0),
       last_offlining_status_(Offliner::RequestStatus::UNKNOWN),
@@ -288,6 +291,14 @@
         network_quality_estimator_->GetEffectiveConnectionType());
   }
 
+  // Record UKM for this page offlining attempt.
+  if (ukm_reporter_) {
+    ukm_reporter_->ReportUrlOfflineRequest(
+        save_page_later_params.url,
+        save_page_later_params.availability ==
+            RequestAvailability::DISABLED_FOR_OFFLINER);
+  }
+
   return id;
 }
 
diff --git a/components/offline_pages/core/background/request_coordinator.h b/components/offline_pages/core/background/request_coordinator.h
index 9f27623..0380b3d 100644
--- a/components/offline_pages/core/background/request_coordinator.h
+++ b/components/offline_pages/core/background/request_coordinator.h
@@ -34,6 +34,7 @@
 class Offliner;
 class SavePageRequest;
 class ClientPolicyController;
+class OfflinePagesUkmReporter;
 
 // Coordinates queueing and processing save page later requests.
 class RequestCoordinator : public KeyedService,
@@ -110,7 +111,8 @@
                      std::unique_ptr<RequestQueue> queue,
                      std::unique_ptr<Scheduler> scheduler,
                      net::NetworkQualityEstimator::NetworkQualityProvider*
-                         network_quality_estimator);
+                         network_quality_estimator,
+                     std::unique_ptr<OfflinePagesUkmReporter> ukm_reporter);
 
   ~RequestCoordinator() override;
 
@@ -447,6 +449,8 @@
   // Unowned pointer to the Network Quality Estimator.
   net::NetworkQualityEstimator::NetworkQualityProvider*
       network_quality_estimator_;
+  // Object that can record Url Keyed Metrics (UKM).
+  std::unique_ptr<OfflinePagesUkmReporter> ukm_reporter_;
   net::EffectiveConnectionType network_quality_at_request_start_;
   // Holds an ID of the currently active request.
   int64_t active_request_id_;
diff --git a/components/offline_pages/core/background/request_coordinator_stub_taco.cc b/components/offline_pages/core/background/request_coordinator_stub_taco.cc
index 3aa3236..acc4453 100644
--- a/components/offline_pages/core/background/request_coordinator_stub_taco.cc
+++ b/components/offline_pages/core/background/request_coordinator_stub_taco.cc
@@ -12,6 +12,7 @@
 #include "components/offline_pages/core/background/save_page_request.h"
 #include "components/offline_pages/core/background/scheduler.h"
 #include "components/offline_pages/core/background/scheduler_stub.h"
+#include "components/offline_pages/core/offline_pages_ukm_reporter_stub.h"
 
 namespace offline_pages {
 
@@ -22,6 +23,7 @@
   offliner_ = base::MakeUnique<OfflinerStub>();
   scheduler_ = base::MakeUnique<SchedulerStub>();
   network_quality_provider_ = base::MakeUnique<NetworkQualityProviderStub>();
+  ukm_reporter_ = base::MakeUnique<OfflinePagesUkmReporterStub>();
 }
 
 RequestCoordinatorStubTaco::~RequestCoordinatorStubTaco() {
@@ -66,10 +68,16 @@
   network_quality_provider_ = std::move(network_quality_provider);
 }
 
+void RequestCoordinatorStubTaco::SetOfflinePagesUkmReporter(
+    std::unique_ptr<offline_pages::OfflinePagesUkmReporter> ukm_reporter) {
+  ukm_reporter_ = std::move(ukm_reporter);
+}
+
 void RequestCoordinatorStubTaco::CreateRequestCoordinator() {
   request_coordinator_ = base::MakeUnique<RequestCoordinator>(
       std::move(policy_), std::move(offliner_), std::move(queue_),
-      std::move(scheduler_), network_quality_provider_.get());
+      std::move(scheduler_), network_quality_provider_.get(),
+      std::move(ukm_reporter_));
 }
 
 RequestCoordinator* RequestCoordinatorStubTaco::request_coordinator() {
diff --git a/components/offline_pages/core/background/request_coordinator_stub_taco.h b/components/offline_pages/core/background/request_coordinator_stub_taco.h
index 58879d1..14f23d5 100644
--- a/components/offline_pages/core/background/request_coordinator_stub_taco.h
+++ b/components/offline_pages/core/background/request_coordinator_stub_taco.h
@@ -40,6 +40,8 @@
   void SetNetworkQualityProvider(
       std::unique_ptr<net::NetworkQualityEstimator::NetworkQualityProvider>
       network_quality_provider);
+  void SetOfflinePagesUkmReporter(
+      std::unique_ptr<OfflinePagesUkmReporter> ukm_reporter);
 
   // Creates and caches an instance of RequestCoordinator, using default or
   // overridden stub dependencies.
@@ -61,6 +63,7 @@
   std::unique_ptr<Scheduler> scheduler_;
   std::unique_ptr<net::NetworkQualityEstimator::NetworkQualityProvider>
       network_quality_provider_;
+  std::unique_ptr<OfflinePagesUkmReporter> ukm_reporter_;
 
   std::unique_ptr<RequestCoordinator> request_coordinator_;
 };
diff --git a/components/offline_pages/core/offline_pages_ukm_reporter.cc b/components/offline_pages/core/offline_pages_ukm_reporter.cc
new file mode 100644
index 0000000..e6e01bb
--- /dev/null
+++ b/components/offline_pages/core/offline_pages_ukm_reporter.cc
@@ -0,0 +1,47 @@
+// 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/offline_pages/core/offline_pages_ukm_reporter.h"
+
+#include "services/metrics/public/cpp/ukm_builders.h"
+#include "services/metrics/public/cpp/ukm_recorder.h"
+#include "url/gurl.h"
+
+namespace offline_pages {
+
+const char OfflinePagesUkmReporter::kRequestUkmEventName[] =
+    "OfflinePages.SavePageRequested";
+const char OfflinePagesUkmReporter::kForegroundUkmMetricName[] =
+    "RequestedFromForeground";
+
+void OfflinePagesUkmReporter::ReportUrlOfflineRequest(const GURL& gurl,
+                                                      bool foreground) {
+  ukm::UkmRecorder* ukm_recorder = ukm::UkmRecorder::Get();
+  if (ukm_recorder == nullptr)
+    return;
+
+  // This unique ID represents this whole navigation.
+  int32_t source_id = ukm::UkmRecorder::GetNewSourceID();
+
+  // Associate the URL with this navigation.
+  ukm_recorder->UpdateSourceURL(source_id, gurl);
+
+  // Tag this metric as an offline page request for the URL.  This is a private
+  // member of UkmRecorder, so we need to be friends to use it.
+  // std::unique_ptr<ukm::UkmEntryBuilder> builder =
+  // ukm_recorder->GetEntryBuilder(
+  //     source_id, OfflinePagesUkmReporter::kRequestUkmEventName);
+  // int metric_value = 0;
+  // if (foreground)
+  //   metric_value = 1;
+  // builder->AddMetric(OfflinePagesUkmReporter::kForegroundUkmMetricName,
+  //                    metric_value);
+
+  // TODO: Change to the new way:
+  ukm::builders::OfflinePages_SavePageRequested(source_id)
+      .SetRequestedFromForeground(foreground ? 1 : 0)
+      .Record(ukm_recorder);
+}
+
+}  // namespace offline_pages
diff --git a/components/offline_pages/core/offline_pages_ukm_reporter.h b/components/offline_pages/core/offline_pages_ukm_reporter.h
new file mode 100644
index 0000000..c644ebf
--- /dev/null
+++ b/components/offline_pages/core/offline_pages_ukm_reporter.h
@@ -0,0 +1,27 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_OFFLINE_PAGES_CORE_OFFLINE_PAGES_UKM_REPORTER_H_
+#define COMPONENTS_OFFLINE_PAGES_CORE_OFFLINE_PAGES_UKM_REPORTER_H_
+
+class GURL;
+
+namespace offline_pages {
+
+// Interface for reporting that a URL has been offlined.  The implementation
+// needs to be in BROWSER code, but the interface is used from COMPONENTS code.
+class OfflinePagesUkmReporter {
+ public:
+  static const char kRequestUkmEventName[];
+  static const char kForegroundUkmMetricName[];
+
+  virtual ~OfflinePagesUkmReporter() = default;
+
+  // Report that an offline copy has been made of this URL.
+  virtual void ReportUrlOfflineRequest(const GURL& gurl, bool foreground);
+};
+
+}  // namespace offline_pages
+
+#endif  // COMPONENTS_OFFLINE_PAGES_CORE_OFFLINE_PAGES_UKM_REPORTER_H_
diff --git a/components/offline_pages/core/offline_pages_ukm_reporter_stub.cc b/components/offline_pages/core/offline_pages_ukm_reporter_stub.cc
new file mode 100644
index 0000000..deaadd3
--- /dev/null
+++ b/components/offline_pages/core/offline_pages_ukm_reporter_stub.cc
@@ -0,0 +1,18 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/offline_pages/core/offline_pages_ukm_reporter_stub.h"
+
+namespace offline_pages {
+
+OfflinePagesUkmReporterStub::OfflinePagesUkmReporterStub()
+    : foreground_(false) {}
+
+void OfflinePagesUkmReporterStub::ReportUrlOfflineRequest(const GURL& gurl,
+                                                          bool foreground) {
+  gurl_ = gurl;
+  foreground_ = foreground;
+}
+
+}  // namespace offline_pages
diff --git a/components/offline_pages/core/offline_pages_ukm_reporter_stub.h b/components/offline_pages/core/offline_pages_ukm_reporter_stub.h
new file mode 100644
index 0000000..4debf09a
--- /dev/null
+++ b/components/offline_pages/core/offline_pages_ukm_reporter_stub.h
@@ -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.
+
+#ifndef COMPONENTS_OFFLINE_PAGES_CORE_OFFLINE_PAGES_UKM_REPORTER_STUB_H_
+#define COMPONENTS_OFFLINE_PAGES_CORE_OFFLINE_PAGES_UKM_REPORTER_STUB_H_
+
+#include "components/offline_pages/core/offline_pages_ukm_reporter.h"
+#include "url/gurl.h"
+
+namespace offline_pages {
+
+class OfflinePagesUkmReporterStub : public OfflinePagesUkmReporter {
+ public:
+  OfflinePagesUkmReporterStub();
+  ~OfflinePagesUkmReporterStub() override = default;
+  void ReportUrlOfflineRequest(const GURL& gurl, bool foreground) override;
+
+  const GURL& GetLastOfflinedUrl() const { return gurl_; }
+  bool GetForeground() const { return foreground_; }
+
+ private:
+  GURL gurl_;
+  bool foreground_;
+};
+
+}  // namespace offline_pages
+
+#endif  // COMPONENTS_OFFLINE_PAGES_CORE_OFFLINE_PAGES_UKM_REPORTER_STUB_H_
diff --git a/components/offline_pages/core/offline_pages_ukm_reporter_unittest.cc b/components/offline_pages/core/offline_pages_ukm_reporter_unittest.cc
new file mode 100644
index 0000000..c494d35
--- /dev/null
+++ b/components/offline_pages/core/offline_pages_ukm_reporter_unittest.cc
@@ -0,0 +1,42 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/offline_pages/core/offline_pages_ukm_reporter.h"
+#include "components/ukm/test_ukm_recorder.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+const char kVisitedUrl[] = "http://m.en.wikipedia.org/wiki/Glider_(sailplane)";
+}  // namespace
+
+namespace offline_pages {
+
+class OfflinePagesUkmReporterTest : public testing::Test {
+ public:
+  ukm::TestUkmRecorder* test_recorder() { return &test_recorder_; }
+
+ private:
+  ukm::TestAutoSetUkmRecorder test_recorder_;
+};
+
+TEST_F(OfflinePagesUkmReporterTest, RecordOfflinePageVisit) {
+  OfflinePagesUkmReporter reporter;
+  GURL gurl(kVisitedUrl);
+
+  reporter.ReportUrlOfflineRequest(gurl, false);
+
+  EXPECT_EQ(1U, test_recorder()->sources_count());
+  const ukm::UkmSource* found_source =
+      test_recorder()->GetSourceForUrl(kVisitedUrl);
+  EXPECT_NE(nullptr, found_source);
+
+  test_recorder()->ExpectMetric(
+      *found_source, ukm::builders::OfflinePages_SavePageRequested::kEntryName,
+      ukm::builders::OfflinePages_SavePageRequested::
+          kRequestedFromForegroundName,
+      0);
+}
+
+}  // namespace offline_pages
diff --git a/components/offline_pages/core/prefetch/import_archives_task_unittest.cc b/components/offline_pages/core/prefetch/import_archives_task_unittest.cc
index 1ab6f462..960975ae 100644
--- a/components/offline_pages/core/prefetch/import_archives_task_unittest.cc
+++ b/components/offline_pages/core/prefetch/import_archives_task_unittest.cc
@@ -58,6 +58,8 @@
 
 }  // namespace
 
+// TODO(carlosk, jianli): Update this test to extend and use the functionality
+// provided by TaskTestBase.
 class ImportArchivesTaskTest : public testing::Test {
  public:
   ImportArchivesTaskTest();
diff --git a/components/payments/core/BUILD.gn b/components/payments/core/BUILD.gn
index 411ccc9..a0ac16cf 100644
--- a/components/payments/core/BUILD.gn
+++ b/components/payments/core/BUILD.gn
@@ -23,8 +23,16 @@
     "journey_logger.h",
     "payment_address.cc",
     "payment_address.h",
+    "payment_currency_amount.cc",
+    "payment_currency_amount.h",
+    "payment_details.cc",
+    "payment_details.h",
+    "payment_details_modifier.cc",
+    "payment_details_modifier.h",
     "payment_instrument.cc",
     "payment_instrument.h",
+    "payment_item.cc",
+    "payment_item.h",
     "payment_manifest_downloader.cc",
     "payment_manifest_downloader.h",
     "payment_method_data.cc",
@@ -36,6 +44,8 @@
     "payment_request_data_util.cc",
     "payment_request_data_util.h",
     "payment_request_delegate.h",
+    "payment_shipping_option.cc",
+    "payment_shipping_option.h",
     "payments_profile_comparator.cc",
     "payments_profile_comparator.h",
     "payments_validators.cc",
@@ -100,9 +110,14 @@
     "currency_formatter_unittest.cc",
     "journey_logger_unittest.cc",
     "payment_address_unittest.cc",
+    "payment_currency_amount_unittest.cc",
+    "payment_details_modifier_unittest.cc",
+    "payment_details_unittest.cc",
+    "payment_item_unittest.cc",
     "payment_manifest_downloader_unittest.cc",
     "payment_method_data_unittest.cc",
     "payment_request_data_util_unittest.cc",
+    "payment_shipping_option_unittest.cc",
     "payments_profile_comparator_unittest.cc",
     "payments_validators_unittest.cc",
     "strings_util_unittest.cc",
diff --git a/components/payments/core/payment_address.h b/components/payments/core/payment_address.h
index 01403fe3..76a5ae01 100644
--- a/components/payments/core/payment_address.h
+++ b/components/payments/core/payment_address.h
@@ -12,7 +12,7 @@
 
 // C++ bindings for the PaymentRequest API PaymentAddress. Conforms to the
 // following spec:
-// https://w3c.github.io/browser-payment-api/#paymentaddress-interface
+// https://w3c.github.io/payment-request/#dom-paymentaddress
 
 namespace base {
 class DictionaryValue;
diff --git a/components/payments/core/payment_address_unittest.cc b/components/payments/core/payment_address_unittest.cc
index 38dac519..67a7c3fe 100644
--- a/components/payments/core/payment_address_unittest.cc
+++ b/components/payments/core/payment_address_unittest.cc
@@ -4,8 +4,6 @@
 
 #include "components/payments/core/payment_address.h"
 
-#include <vector>
-
 #include "base/strings/utf_string_conversions.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/components/payments/core/payment_currency_amount.cc b/components/payments/core/payment_currency_amount.cc
new file mode 100644
index 0000000..40ca4cb
--- /dev/null
+++ b/components/payments/core/payment_currency_amount.cc
@@ -0,0 +1,73 @@
+// 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/payments/core/payment_currency_amount.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+
+namespace payments {
+
+namespace {
+
+// These are defined as part of the spec at:
+// https://w3c.github.io/browser-payment-api/#dom-paymentcurrencyamount
+static const char kPaymentCurrencyAmountCurrencySystemISO4217[] =
+    "urn:iso:std:iso:4217";
+static const char kPaymentCurrencyAmountCurrencySystem[] = "currencySystem";
+static const char kPaymentCurrencyAmountCurrency[] = "currency";
+static const char kPaymentCurrencyAmountValue[] = "value";
+
+}  // namespace
+
+PaymentCurrencyAmount::PaymentCurrencyAmount()
+    // By default, the currency is defined by [ISO4217]. For example, USD for
+    // US Dollars.
+    : currency_system(
+          base::ASCIIToUTF16(kPaymentCurrencyAmountCurrencySystemISO4217)) {}
+
+PaymentCurrencyAmount::~PaymentCurrencyAmount() = default;
+
+bool PaymentCurrencyAmount::operator==(
+    const PaymentCurrencyAmount& other) const {
+  return this->currency == other.currency && this->value == other.value;
+}
+
+bool PaymentCurrencyAmount::operator!=(
+    const PaymentCurrencyAmount& other) const {
+  return !(*this == other);
+}
+
+bool PaymentCurrencyAmount::FromDictionaryValue(
+    const base::DictionaryValue& value) {
+  if (!value.GetString(kPaymentCurrencyAmountCurrency, &this->currency)) {
+    return false;
+  }
+
+  if (!value.GetString(kPaymentCurrencyAmountValue, &this->value)) {
+    return false;
+  }
+
+  // Currency_system is optional
+  value.GetString(kPaymentCurrencyAmountCurrencySystem, &this->currency_system);
+
+  return true;
+}
+
+std::unique_ptr<base::DictionaryValue>
+PaymentCurrencyAmount::ToDictionaryValue() const {
+  std::unique_ptr<base::DictionaryValue> result =
+      base::MakeUnique<base::DictionaryValue>();
+
+  result->SetString(kPaymentCurrencyAmountCurrency, this->currency);
+  result->SetString(kPaymentCurrencyAmountValue, this->value);
+  if (!this->currency_system.empty())
+    result->SetString(kPaymentCurrencyAmountCurrencySystem,
+                      this->currency_system);
+
+  return result;
+}
+
+}  // namespace payments
diff --git a/components/payments/core/payment_currency_amount.h b/components/payments/core/payment_currency_amount.h
new file mode 100644
index 0000000..64cb242
--- /dev/null
+++ b/components/payments/core/payment_currency_amount.h
@@ -0,0 +1,54 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_PAYMENTS_CORE_PAYMENT_CURRENCY_AMOUNT_H_
+#define COMPONENTS_PAYMENTS_CORE_PAYMENT_CURRENCY_AMOUNT_H_
+
+#include <memory>
+
+#include "base/strings/string16.h"
+
+// C++ bindings for the PaymentRequest API PaymentCurrencyAmount. Conforms to
+// the following spec:
+// https://w3c.github.io/browser-payment-api/#dom-paymentcurrencyamount
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace payments {
+
+// Supplies monetary amounts.
+class PaymentCurrencyAmount {
+ public:
+  PaymentCurrencyAmount();
+  ~PaymentCurrencyAmount();
+
+  bool operator==(const PaymentCurrencyAmount& other) const;
+  bool operator!=(const PaymentCurrencyAmount& other) const;
+
+  // Populates the properties of this PaymentCurrencyAmount from |value|.
+  // Returns true if the required values are present.
+  bool FromDictionaryValue(const base::DictionaryValue& value);
+
+  // Creates a base::DictionaryValue with the properties of this
+  // PaymentCurrencyAmount.
+  std::unique_ptr<base::DictionaryValue> ToDictionaryValue() const;
+
+  // A currency identifier. The most common identifiers are three-letter
+  // alphabetic codes as defined by ISO 4217 (for example, "USD" for US Dollars)
+  // however any string is considered valid.
+  base::string16 currency;
+
+  // A string containing the decimal monetary value.
+  base::string16 value;
+
+  // A URL that indicates the currency system that the currency identifier
+  // belongs to.
+  base::string16 currency_system;
+};
+
+}  // namespace payments
+
+#endif  // COMPONENTS_PAYMENTS_CORE_PAYMENT_CURRENCY_AMOUNT_H_
diff --git a/components/payments/core/payment_currency_amount_unittest.cc b/components/payments/core/payment_currency_amount_unittest.cc
new file mode 100644
index 0000000..d2277367
--- /dev/null
+++ b/components/payments/core/payment_currency_amount_unittest.cc
@@ -0,0 +1,108 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/payments/core/payment_currency_amount.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace payments {
+
+// Tests the success case when populating a PaymentCurrencyAmount from a
+// dictionary.
+TEST(PaymentRequestTest, PaymentCurrencyAmountFromDictionaryValueSuccess) {
+  PaymentCurrencyAmount expected;
+  expected.currency = base::ASCIIToUTF16("AUD");
+  expected.value = base::ASCIIToUTF16("-438.23");
+
+  base::DictionaryValue amount_dict;
+  amount_dict.SetString("currency", "AUD");
+  amount_dict.SetString("value", "-438.23");
+
+  PaymentCurrencyAmount actual;
+  EXPECT_TRUE(actual.FromDictionaryValue(amount_dict));
+
+  EXPECT_EQ(expected, actual);
+
+  expected.currency_system = base::ASCIIToUTF16("urn:iso:std:iso:123456789");
+  amount_dict.SetString("currencySystem", "urn:iso:std:iso:123456789");
+  EXPECT_TRUE(actual.FromDictionaryValue(amount_dict));
+  EXPECT_EQ(expected, actual);
+}
+
+// Tests the failure case when populating a PaymentCurrencyAmount from a
+// dictionary.
+TEST(PaymentRequestTest, PaymentCurrencyAmountFromDictionaryValueFailure) {
+  // Both a currency and a value are required.
+  PaymentCurrencyAmount actual;
+  base::DictionaryValue amount_dict;
+  EXPECT_FALSE(actual.FromDictionaryValue(amount_dict));
+
+  // Both values must be strings.
+  amount_dict.SetInteger("currency", 842);
+  amount_dict.SetString("value", "-438.23");
+  EXPECT_FALSE(actual.FromDictionaryValue(amount_dict));
+
+  amount_dict.SetString("currency", "NZD");
+  amount_dict.SetDouble("value", -438.23);
+  EXPECT_FALSE(actual.FromDictionaryValue(amount_dict));
+}
+
+// Tests that two currency amount objects are not equal if their property values
+// differ or one is missing a value present in the other, and equal otherwise.
+TEST(PaymentRequestTest, PaymentCurrencyAmountEquality) {
+  PaymentCurrencyAmount currency_amount1;
+  PaymentCurrencyAmount currency_amount2;
+  EXPECT_EQ(currency_amount1, currency_amount2);
+
+  currency_amount1.currency = base::ASCIIToUTF16("HKD");
+  EXPECT_NE(currency_amount1, currency_amount2);
+  currency_amount2.currency = base::ASCIIToUTF16("USD");
+  EXPECT_NE(currency_amount1, currency_amount2);
+  currency_amount2.currency = base::ASCIIToUTF16("HKD");
+  EXPECT_EQ(currency_amount1, currency_amount2);
+
+  currency_amount1.value = base::ASCIIToUTF16("49.89");
+  EXPECT_NE(currency_amount1, currency_amount2);
+  currency_amount2.value = base::ASCIIToUTF16("49.99");
+  EXPECT_NE(currency_amount1, currency_amount2);
+  currency_amount2.value = base::ASCIIToUTF16("49.89");
+  EXPECT_EQ(currency_amount1, currency_amount2);
+}
+
+// Tests that serializing a default PaymentCurrencyAmount yields the expected
+// result.
+TEST(PaymentRequestTest, EmptyPaymentCurrencyAmountDictionary) {
+  base::DictionaryValue expected_value;
+
+  expected_value.SetString("currency", "");
+  expected_value.SetString("value", "");
+  expected_value.SetString("currencySystem", "urn:iso:std:iso:4217");
+
+  PaymentCurrencyAmount payment_currency_amount;
+  EXPECT_TRUE(
+      expected_value.Equals(payment_currency_amount.ToDictionaryValue().get()));
+}
+
+// Tests that serializing a populated PaymentCurrencyAmount yields the expected
+// result.
+TEST(PaymentRequestTest, PopulatedCurrencyAmountDictionary) {
+  base::DictionaryValue expected_value;
+
+  expected_value.SetString("currency", "AUD");
+  expected_value.SetString("value", "-438.23");
+  expected_value.SetString("currencySystem", "urn:iso:std:iso:123456789");
+
+  PaymentCurrencyAmount payment_currency_amount;
+  payment_currency_amount.currency = base::ASCIIToUTF16("AUD");
+  payment_currency_amount.value = base::ASCIIToUTF16("-438.23");
+  payment_currency_amount.currency_system =
+      base::ASCIIToUTF16("urn:iso:std:iso:123456789");
+
+  EXPECT_TRUE(
+      expected_value.Equals(payment_currency_amount.ToDictionaryValue().get()));
+}
+
+}  // namespace payments
diff --git a/components/payments/core/payment_details.cc b/components/payments/core/payment_details.cc
new file mode 100644
index 0000000..04e382b7
--- /dev/null
+++ b/components/payments/core/payment_details.cc
@@ -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.
+
+#include "components/payments/core/payment_details.h"
+
+#include "base/values.h"
+
+namespace payments {
+
+namespace {
+
+// These are defined as part of the spec at:
+// https://w3c.github.io/payment-request/#payment-details-dictionaries
+static const char kPaymentDetailsId[] = "id";
+static const char kPaymentDetailsDisplayItems[] = "displayItems";
+static const char kPaymentDetailsError[] = "error";
+static const char kPaymentDetailsShippingOptions[] = "shippingOptions";
+static const char kPaymentDetailsTotal[] = "total";
+
+}  // namespace
+
+PaymentDetails::PaymentDetails() {}
+PaymentDetails::PaymentDetails(const PaymentDetails& other) = default;
+PaymentDetails::~PaymentDetails() = default;
+
+bool PaymentDetails::operator==(const PaymentDetails& other) const {
+  return this->id == other.id && this->total == other.total &&
+         this->display_items == other.display_items &&
+         this->shipping_options == other.shipping_options &&
+         this->modifiers == other.modifiers && this->error == other.error;
+}
+
+bool PaymentDetails::operator!=(const PaymentDetails& other) const {
+  return !(*this == other);
+}
+
+bool PaymentDetails::FromDictionaryValue(const base::DictionaryValue& value,
+                                         bool requires_total) {
+  this->display_items.clear();
+  this->shipping_options.clear();
+  this->modifiers.clear();
+
+  // ID is optional.
+  value.GetString(kPaymentDetailsId, &this->id);
+
+  const base::DictionaryValue* total_dict = nullptr;
+  if (!value.GetDictionary(kPaymentDetailsTotal, &total_dict) &&
+      requires_total) {
+    return false;
+  }
+  if (total_dict && !this->total.FromDictionaryValue(*total_dict)) {
+    return false;
+  }
+
+  const base::ListValue* display_items_list = nullptr;
+  if (value.GetList(kPaymentDetailsDisplayItems, &display_items_list)) {
+    for (size_t i = 0; i < display_items_list->GetSize(); ++i) {
+      const base::DictionaryValue* payment_item_dict;
+      if (!display_items_list->GetDictionary(i, &payment_item_dict)) {
+        return false;
+      }
+      PaymentItem payment_item;
+      if (!payment_item.FromDictionaryValue(*payment_item_dict)) {
+        return false;
+      }
+      this->display_items.push_back(payment_item);
+    }
+  }
+
+  const base::ListValue* shipping_options_list = nullptr;
+  if (value.GetList(kPaymentDetailsShippingOptions, &shipping_options_list)) {
+    for (size_t i = 0; i < shipping_options_list->GetSize(); ++i) {
+      const base::DictionaryValue* shipping_option_dict;
+      if (!shipping_options_list->GetDictionary(i, &shipping_option_dict)) {
+        return false;
+      }
+      PaymentShippingOption shipping_option;
+      if (!shipping_option.FromDictionaryValue(*shipping_option_dict)) {
+        return false;
+      }
+      this->shipping_options.push_back(shipping_option);
+    }
+  }
+
+  // Error is optional.
+  value.GetString(kPaymentDetailsError, &this->error);
+
+  return true;
+}
+
+}  // namespace payments
diff --git a/components/payments/core/payment_details.h b/components/payments/core/payment_details.h
new file mode 100644
index 0000000..c650033
--- /dev/null
+++ b/components/payments/core/payment_details.h
@@ -0,0 +1,68 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_PAYMENTS_CORE_PAYMENT_DETAILS_H_
+#define COMPONENTS_PAYMENTS_CORE_PAYMENT_DETAILS_H_
+
+#include <string>
+#include <vector>
+
+#include "base/strings/string16.h"
+#include "components/payments/core/payment_details_modifier.h"
+#include "components/payments/core/payment_item.h"
+#include "components/payments/core/payment_shipping_option.h"
+
+// C++ bindings for the PaymentRequest API PaymentDetails. Conforms to the
+// following spec:
+// https://w3c.github.io/payment-request/#payment-details-dictionaries
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace payments {
+
+// Details about the requested transaction.
+class PaymentDetails {
+ public:
+  PaymentDetails();
+  PaymentDetails(const PaymentDetails& other);
+  ~PaymentDetails();
+
+  bool operator==(const PaymentDetails& other) const;
+  bool operator!=(const PaymentDetails& other) const;
+
+  // Populates the properties of this PaymentDetails from |value|. Returns true
+  // if the required values are present. If |requires_total| is true, the total
+  // property has to be present.
+  bool FromDictionaryValue(const base::DictionaryValue& value,
+                           bool requires_total);
+
+  // The unique free-form identifier for this payment request.
+  std::string id;
+
+  // The total amount of the payment request.
+  PaymentItem total;
+
+  // Line items for the payment request that the user agent may display. For
+  // example, it might include details of products or breakdown of tax and
+  // shipping.
+  std::vector<PaymentItem> display_items;
+
+  // The different shipping options for the user to choose from. If empty, this
+  // indicates that the merchant cannot ship to the current shipping address.
+  std::vector<PaymentShippingOption> shipping_options;
+
+  // Modifiers for particular payment method identifiers. For example, it allows
+  // adjustment to the total amount based on payment method.
+  std::vector<PaymentDetailsModifier> modifiers;
+
+  // If non-empty, this is the error message the user agent should display to
+  // the user when the payment request is updated using updateWith.
+  base::string16 error;
+};
+
+}  // namespace payments
+
+#endif  // COMPONENTS_PAYMENTS_CORE_PAYMENT_DETAILS_H_
diff --git a/components/payments/core/payment_details_modifier.cc b/components/payments/core/payment_details_modifier.cc
new file mode 100644
index 0000000..8ed516c
--- /dev/null
+++ b/components/payments/core/payment_details_modifier.cc
@@ -0,0 +1,57 @@
+// 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/payments/core/payment_details_modifier.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/values.h"
+
+namespace payments {
+
+namespace {
+
+// These are defined as part of the spec at:
+// https://w3c.github.io/payment-request/#dom-paymentdetailsmodifier
+static const char kPaymentDetailsModifierTotal[] = "total";
+static const char kPaymentDetailsModifierSupportedMethods[] =
+    "supportedMethods";
+
+}  // namespace
+
+PaymentDetailsModifier::PaymentDetailsModifier() {}
+PaymentDetailsModifier::PaymentDetailsModifier(
+    const PaymentDetailsModifier& other) = default;
+PaymentDetailsModifier::~PaymentDetailsModifier() = default;
+
+bool PaymentDetailsModifier::operator==(
+    const PaymentDetailsModifier& other) const {
+  return this->supported_methods == other.supported_methods &&
+         this->total == other.total &&
+         this->additional_display_items == other.additional_display_items;
+}
+
+bool PaymentDetailsModifier::operator!=(
+    const PaymentDetailsModifier& other) const {
+  return !(*this == other);
+}
+
+std::unique_ptr<base::DictionaryValue>
+PaymentDetailsModifier::ToDictionaryValue() const {
+  std::unique_ptr<base::DictionaryValue> result =
+      base::MakeUnique<base::DictionaryValue>();
+
+  std::unique_ptr<base::ListValue> methods =
+      base::MakeUnique<base::ListValue>();
+  size_t numMethods = this->supported_methods.size();
+  for (size_t i = 0; i < numMethods; i++) {
+    methods->GetList().emplace_back(this->supported_methods[i]);
+  }
+  result->SetList(kPaymentDetailsModifierSupportedMethods, std::move(methods));
+  result->SetDictionary(kPaymentDetailsModifierTotal,
+                        this->total.ToDictionaryValue());
+
+  return result;
+}
+
+}  // namespace payments
diff --git a/components/payments/core/payment_details_modifier.h b/components/payments/core/payment_details_modifier.h
new file mode 100644
index 0000000..2bbd5c27
--- /dev/null
+++ b/components/payments/core/payment_details_modifier.h
@@ -0,0 +1,59 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_PAYMENTS_CORE_PAYMENT_DETAILS_MODIFIER_H_
+#define COMPONENTS_PAYMENTS_CORE_PAYMENT_DETAILS_MODIFIER_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/strings/string16.h"
+#include "components/payments/core/payment_item.h"
+
+// C++ bindings for the PaymentRequest API PaymentDetailsModifier. Conforms to
+// the following spec:
+// https://w3c.github.io/payment-request/#dom-paymentdetailsmodifier
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace payments {
+
+// Details that modify the PaymentDetails based on the payment method
+// identifier.
+class PaymentDetailsModifier {
+ public:
+  PaymentDetailsModifier();
+  PaymentDetailsModifier(const PaymentDetailsModifier& other);
+  ~PaymentDetailsModifier();
+
+  bool operator==(const PaymentDetailsModifier& other) const;
+  bool operator!=(const PaymentDetailsModifier& other) const;
+
+  // Creates a base::DictionaryValue with the properties of this
+  // PaymentDetailsModifier.
+  std::unique_ptr<base::DictionaryValue> ToDictionaryValue() const;
+
+  // A sequence of payment method identifiers. The remaining fields in the
+  // PaymentDetailsModifier apply only if the user selects a payment method
+  // included in this sequence.
+  std::vector<base::string16> supported_methods;
+
+  // This value overrides the total field in the PaymentDetails dictionary for
+  // the payment method identifiers in the supportedMethods field.
+  payments::PaymentItem total;
+
+  // Provides additional display items that are appended to the displayItems
+  // field in the PaymentDetails dictionary for the payment method identifiers
+  // in the supportedMethods field. This field is commonly used to add a
+  // discount or surcharge line item indicating the reason for the different
+  // total amount for the selected payment method that the user agent may
+  // display.
+  std::vector<payments::PaymentItem> additional_display_items;
+};
+
+}  // namespace payments
+
+#endif  // COMPONENTS_PAYMENTS_CORE_PAYMENT_DETAILS_MODIFIER_H_
diff --git a/components/payments/core/payment_details_modifier_unittest.cc b/components/payments/core/payment_details_modifier_unittest.cc
new file mode 100644
index 0000000..4035a33
--- /dev/null
+++ b/components/payments/core/payment_details_modifier_unittest.cc
@@ -0,0 +1,117 @@
+// 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/payments/core/payment_details_modifier.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace payments {
+
+// Tests that serializing a default PaymentDetailsModifier yields the expected
+// result.
+TEST(PaymentRequestTest, EmptyPaymentDetailsModifierDictionary) {
+  base::DictionaryValue expected_value;
+
+  std::unique_ptr<base::ListValue> supported_methods_list =
+      base::MakeUnique<base::ListValue>();
+  expected_value.SetList("supportedMethods", std::move(supported_methods_list));
+  std::unique_ptr<base::DictionaryValue> item_dict =
+      base::MakeUnique<base::DictionaryValue>();
+  item_dict->SetString("label", "");
+  std::unique_ptr<base::DictionaryValue> amount_dict =
+      base::MakeUnique<base::DictionaryValue>();
+  amount_dict->SetString("currency", "");
+  amount_dict->SetString("value", "");
+  amount_dict->SetString("currencySystem", "urn:iso:std:iso:4217");
+  item_dict->SetDictionary("amount", std::move(amount_dict));
+  item_dict->SetBoolean("pending", false);
+  expected_value.SetDictionary("total", std::move(item_dict));
+
+  PaymentDetailsModifier payment_detials_modififer;
+  EXPECT_TRUE(expected_value.Equals(
+      payment_detials_modififer.ToDictionaryValue().get()));
+}
+
+// Tests that serializing a populated PaymentDetailsModifier yields the expected
+// result.
+TEST(PaymentRequestTest, PopulatedDetailsModifierDictionary) {
+  base::DictionaryValue expected_value;
+
+  std::unique_ptr<base::ListValue> supported_methods_list =
+      base::MakeUnique<base::ListValue>();
+  supported_methods_list->GetList().emplace_back("visa");
+  supported_methods_list->GetList().emplace_back("amex");
+  expected_value.SetList("supportedMethods", std::move(supported_methods_list));
+  std::unique_ptr<base::DictionaryValue> item_dict =
+      base::MakeUnique<base::DictionaryValue>();
+  item_dict->SetString("label", "Gratuity");
+  std::unique_ptr<base::DictionaryValue> amount_dict =
+      base::MakeUnique<base::DictionaryValue>();
+  amount_dict->SetString("currency", "USD");
+  amount_dict->SetString("value", "139.99");
+  amount_dict->SetString("currencySystem", "urn:iso:std:iso:4217");
+  item_dict->SetDictionary("amount", std::move(amount_dict));
+  item_dict->SetBoolean("pending", false);
+  expected_value.SetDictionary("total", std::move(item_dict));
+
+  PaymentDetailsModifier payment_detials_modififer;
+  payment_detials_modififer.supported_methods.push_back(
+      base::ASCIIToUTF16("visa"));
+  payment_detials_modififer.supported_methods.push_back(
+      base::ASCIIToUTF16("amex"));
+  payment_detials_modififer.total.label = base::ASCIIToUTF16("Gratuity");
+  payment_detials_modififer.total.amount.currency = base::ASCIIToUTF16("USD");
+  payment_detials_modififer.total.amount.value = base::ASCIIToUTF16("139.99");
+
+  EXPECT_TRUE(expected_value.Equals(
+      payment_detials_modififer.ToDictionaryValue().get()));
+}
+
+// Tests that two details modifier objects are not equal if their property
+// values differ or one is missing a value present in the other, and equal
+// otherwise. Doesn't test all properties of child objects, relying instead on
+// their respective tests.
+TEST(PaymentRequestTest, PaymentDetailsModifierEquality) {
+  PaymentDetailsModifier details_modifier1;
+  PaymentDetailsModifier details_modifier2;
+  EXPECT_EQ(details_modifier1, details_modifier2);
+
+  std::vector<base::string16> supported_methods1;
+  supported_methods1.push_back(base::ASCIIToUTF16("China UnionPay"));
+  supported_methods1.push_back(base::ASCIIToUTF16("BobPay"));
+  details_modifier1.supported_methods = supported_methods1;
+  EXPECT_NE(details_modifier1, details_modifier2);
+  std::vector<base::string16> supported_methods2;
+  supported_methods2.push_back(base::ASCIIToUTF16("BobPay"));
+  details_modifier2.supported_methods = supported_methods2;
+  EXPECT_NE(details_modifier1, details_modifier2);
+  details_modifier2.supported_methods = supported_methods1;
+  EXPECT_EQ(details_modifier1, details_modifier2);
+
+  details_modifier1.total.label = base::ASCIIToUTF16("Total");
+  EXPECT_NE(details_modifier1, details_modifier2);
+  details_modifier2.total.label = base::ASCIIToUTF16("Gratuity");
+  EXPECT_NE(details_modifier1, details_modifier2);
+  details_modifier2.total.label = base::ASCIIToUTF16("Total");
+  EXPECT_EQ(details_modifier1, details_modifier2);
+
+  PaymentItem payment_item;
+  payment_item.label = base::ASCIIToUTF16("Tax");
+  std::vector<PaymentItem> display_items1;
+  display_items1.push_back(payment_item);
+  details_modifier1.additional_display_items = display_items1;
+  EXPECT_NE(details_modifier1, details_modifier2);
+  std::vector<PaymentItem> display_items2;
+  display_items2.push_back(payment_item);
+  display_items2.push_back(payment_item);
+  details_modifier2.additional_display_items = display_items2;
+  EXPECT_NE(details_modifier1, details_modifier2);
+  details_modifier2.additional_display_items = display_items1;
+  EXPECT_EQ(details_modifier1, details_modifier2);
+}
+
+}  // namespace payments
diff --git a/components/payments/core/payment_details_unittest.cc b/components/payments/core/payment_details_unittest.cc
new file mode 100644
index 0000000..a520027
--- /dev/null
+++ b/components/payments/core/payment_details_unittest.cc
@@ -0,0 +1,135 @@
+// 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/payments/core/payment_details.h"
+
+#include <memory>
+
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace payments {
+
+// Tests the success case when populating a PaymentDetails from a dictionary.
+TEST(PaymentRequestTest, PaymentDetailsFromDictionaryValueSuccess) {
+  PaymentDetails expected;
+  expected.error = base::ASCIIToUTF16("Error in details");
+
+  base::DictionaryValue details_dict;
+  details_dict.SetString("error", "Error in details");
+  PaymentDetails actual;
+  EXPECT_TRUE(
+      actual.FromDictionaryValue(details_dict, /*requires_total=*/false));
+  EXPECT_EQ(expected, actual);
+
+  expected.total.label = base::ASCIIToUTF16("TOTAL");
+  expected.total.amount.currency = base::ASCIIToUTF16("GBP");
+  expected.total.amount.value = base::ASCIIToUTF16("6.66");
+
+  std::unique_ptr<base::DictionaryValue> total_dict(new base::DictionaryValue);
+  total_dict->SetString("label", "TOTAL");
+  std::unique_ptr<base::DictionaryValue> amount_dict(new base::DictionaryValue);
+  amount_dict->SetString("currency", "GBP");
+  amount_dict->SetString("value", "6.66");
+  total_dict->Set("amount", std::move(amount_dict));
+  details_dict.Set("total", std::move(total_dict));
+
+  EXPECT_TRUE(
+      actual.FromDictionaryValue(details_dict, /*requires_total=*/false));
+  EXPECT_EQ(expected, actual);
+
+  EXPECT_TRUE(
+      actual.FromDictionaryValue(details_dict, /*requires_total=*/true));
+  EXPECT_EQ(expected, actual);
+}
+
+// Tests the failure case when populating a PaymentDetails from a dictionary.
+TEST(PaymentRequestTest, PaymentDetailsFromDictionaryValueFailure) {
+  PaymentDetails expected;
+  expected.total.label = base::ASCIIToUTF16("TOTAL");
+  expected.total.amount.currency = base::ASCIIToUTF16("GBP");
+  expected.total.amount.value = base::ASCIIToUTF16("6.66");
+  expected.error = base::ASCIIToUTF16("Error in details");
+
+  base::DictionaryValue details_dict;
+  details_dict.SetString("error", "Error in details");
+
+  PaymentDetails actual;
+  EXPECT_FALSE(
+      actual.FromDictionaryValue(details_dict, /*requires_total=*/true));
+}
+
+// Tests that two payment details objects are not equal if their property values
+// differ or one is missing a value present in the other, and equal otherwise.
+// Doesn't test all properties of child objects, relying instead on their
+// respective tests.
+TEST(PaymentRequestTest, PaymentDetailsEquality) {
+  PaymentDetails details1;
+  PaymentDetails details2;
+  EXPECT_EQ(details1, details2);
+
+  details1.id = "12345";
+  EXPECT_NE(details1, details2);
+  details2.id = "54321";
+  EXPECT_NE(details1, details2);
+  details2.id = details1.id;
+  EXPECT_EQ(details1, details2);
+
+  details1.total.label = base::ASCIIToUTF16("Total");
+  EXPECT_NE(details1, details2);
+  details2.total.label = base::ASCIIToUTF16("Shipping");
+  EXPECT_NE(details1, details2);
+  details2.total.label = base::ASCIIToUTF16("Total");
+  EXPECT_EQ(details1, details2);
+
+  details1.error = base::ASCIIToUTF16("Foo");
+  EXPECT_NE(details1, details2);
+  details2.error = base::ASCIIToUTF16("Bar");
+  EXPECT_NE(details1, details2);
+  details2.error = base::ASCIIToUTF16("Foo");
+  EXPECT_EQ(details1, details2);
+
+  PaymentItem payment_item;
+  payment_item.label = base::ASCIIToUTF16("Tax");
+  std::vector<PaymentItem> display_items1;
+  display_items1.push_back(payment_item);
+  details1.display_items = display_items1;
+  EXPECT_NE(details1, details2);
+  std::vector<PaymentItem> display_items2;
+  display_items2.push_back(payment_item);
+  display_items2.push_back(payment_item);
+  details2.display_items = display_items2;
+  EXPECT_NE(details1, details2);
+  details2.display_items = display_items1;
+  EXPECT_EQ(details1, details2);
+
+  PaymentShippingOption shipping_option;
+  shipping_option.label = base::ASCIIToUTF16("Overnight");
+  std::vector<PaymentShippingOption> shipping_options1;
+  shipping_options1.push_back(shipping_option);
+  details1.shipping_options = shipping_options1;
+  EXPECT_NE(details1, details2);
+  std::vector<PaymentShippingOption> shipping_options2;
+  shipping_options2.push_back(shipping_option);
+  shipping_options2.push_back(shipping_option);
+  details2.shipping_options = shipping_options2;
+  EXPECT_NE(details1, details2);
+  details2.shipping_options = shipping_options1;
+  EXPECT_EQ(details1, details2);
+
+  PaymentDetailsModifier details_modifier;
+  details_modifier.total.label = base::ASCIIToUTF16("Total");
+  std::vector<PaymentDetailsModifier> details_modifiers1;
+  details_modifiers1.push_back(details_modifier);
+  details1.modifiers = details_modifiers1;
+  EXPECT_NE(details1, details2);
+  std::vector<PaymentDetailsModifier> details_modifiers2;
+  details2.modifiers = details_modifiers2;
+  EXPECT_NE(details1, details2);
+  details2.modifiers = details_modifiers1;
+  EXPECT_EQ(details1, details2);
+}
+
+}  // namespace payments
diff --git a/components/payments/core/payment_item.cc b/components/payments/core/payment_item.cc
new file mode 100644
index 0000000..d8775a8
--- /dev/null
+++ b/components/payments/core/payment_item.cc
@@ -0,0 +1,64 @@
+// 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/payments/core/payment_item.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/values.h"
+
+namespace payments {
+
+namespace {
+
+// These are defined as part of the spec at:
+// https://w3c.github.io/payment-request/#dom-paymentitem
+static const char kPaymentItemAmount[] = "amount";
+static const char kPaymentItemLabel[] = "label";
+static const char kPaymentItemPending[] = "pending";
+
+}  // namespace
+
+PaymentItem::PaymentItem() : pending(false) {}
+PaymentItem::~PaymentItem() = default;
+
+bool PaymentItem::operator==(const PaymentItem& other) const {
+  return this->label == other.label && this->amount == other.amount &&
+         this->pending == other.pending;
+}
+
+bool PaymentItem::operator!=(const PaymentItem& other) const {
+  return !(*this == other);
+}
+
+bool PaymentItem::FromDictionaryValue(const base::DictionaryValue& value) {
+  if (!value.GetString(kPaymentItemLabel, &this->label)) {
+    return false;
+  }
+
+  const base::DictionaryValue* amount_dict = nullptr;
+  if (!value.GetDictionary(kPaymentItemAmount, &amount_dict)) {
+    return false;
+  }
+  if (!this->amount.FromDictionaryValue(*amount_dict)) {
+    return false;
+  }
+
+  // Pending is optional.
+  value.GetBoolean(kPaymentItemPending, &this->pending);
+
+  return true;
+}
+
+std::unique_ptr<base::DictionaryValue> PaymentItem::ToDictionaryValue() const {
+  std::unique_ptr<base::DictionaryValue> result =
+      base::MakeUnique<base::DictionaryValue>();
+
+  result->SetString(kPaymentItemLabel, this->label);
+  result->SetDictionary(kPaymentItemAmount, this->amount.ToDictionaryValue());
+  result->SetBoolean(kPaymentItemPending, this->pending);
+
+  return result;
+}
+
+}  // namespace payments
diff --git a/components/payments/core/payment_item.h b/components/payments/core/payment_item.h
new file mode 100644
index 0000000..f4b6b41
--- /dev/null
+++ b/components/payments/core/payment_item.h
@@ -0,0 +1,55 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_PAYMENTS_CORE_PAYMENT_ITEM_H_
+#define COMPONENTS_PAYMENTS_CORE_PAYMENT_ITEM_H_
+
+#include <memory>
+
+#include "base/strings/string16.h"
+#include "components/payments/core/payment_currency_amount.h"
+
+// C++ bindings for the PaymentRequest API PaymentItem. Conforms to the
+// following spec:
+// https://w3c.github.io/payment-request/#dom-paymentitem
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace payments {
+
+// Information indicating what the payment request is for and the value asked
+// for.
+class PaymentItem {
+ public:
+  PaymentItem();
+  ~PaymentItem();
+
+  bool operator==(const PaymentItem& other) const;
+  bool operator!=(const PaymentItem& other) const;
+
+  // Populates the properties of this PaymentItem from |value|. Returns true if
+  // the required values are present.
+  bool FromDictionaryValue(const base::DictionaryValue& value);
+
+  // Creates a base::DictionaryValue with the properties of this
+  // PaymentItem.
+  std::unique_ptr<base::DictionaryValue> ToDictionaryValue() const;
+
+  // A human-readable description of the item.
+  base::string16 label;
+
+  // The monetary amount for the item.
+  PaymentCurrencyAmount amount;
+
+  // When set to true this flag means that the amount field is not final. This
+  // is commonly used to show items such as shipping or tax amounts that depend
+  // upon selection of shipping address or shipping option.
+  bool pending;
+};
+
+}  // namespace payments
+
+#endif  // COMPONENTS_PAYMENTS_CORE_PAYMENT_ITEM_H_
diff --git a/components/payments/core/payment_item_unittest.cc b/components/payments/core/payment_item_unittest.cc
new file mode 100644
index 0000000..78a1b215
--- /dev/null
+++ b/components/payments/core/payment_item_unittest.cc
@@ -0,0 +1,121 @@
+// 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/payments/core/payment_item.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace payments {
+
+// Tests the success case when populating a PaymentItem from a dictionary.
+TEST(PaymentRequestTest, PaymentItemFromDictionaryValueSuccess) {
+  PaymentItem expected;
+  expected.label = base::ASCIIToUTF16("Payment Total");
+  expected.amount.currency = base::ASCIIToUTF16("NZD");
+  expected.amount.value = base::ASCIIToUTF16("2,242,093.00");
+
+  base::DictionaryValue item_dict;
+  item_dict.SetString("label", "Payment Total");
+  std::unique_ptr<base::DictionaryValue> amount_dict(new base::DictionaryValue);
+  amount_dict->SetString("currency", "NZD");
+  amount_dict->SetString("value", "2,242,093.00");
+  item_dict.Set("amount", std::move(amount_dict));
+
+  PaymentItem actual;
+  EXPECT_TRUE(actual.FromDictionaryValue(item_dict));
+
+  EXPECT_EQ(expected, actual);
+}
+
+// Tests the failure case when populating a PaymentItem from a dictionary.
+TEST(PaymentRequestTest, PaymentItemFromDictionaryValueFailure) {
+  // Both a label and an amount are required.
+  PaymentItem actual;
+  base::DictionaryValue item_dict;
+  EXPECT_FALSE(actual.FromDictionaryValue(item_dict));
+
+  item_dict.SetString("label", "Payment Total");
+  EXPECT_FALSE(actual.FromDictionaryValue(item_dict));
+
+  // Even with both present, the label must be a string.
+  std::unique_ptr<base::DictionaryValue> amount_dict(new base::DictionaryValue);
+  amount_dict->SetString("currency", "NZD");
+  amount_dict->SetString("value", "2,242,093.00");
+  item_dict.Set("amount", std::move(amount_dict));
+  item_dict.SetInteger("label", 42);
+  EXPECT_FALSE(actual.FromDictionaryValue(item_dict));
+}
+
+// Tests that two payment item objects are not equal if their property values
+// differ or one is missing a value present in the other, and equal otherwise.
+// Doesn't test all properties of child objects, relying instead on their
+// respective tests.
+TEST(PaymentRequestTest, PaymentItemEquality) {
+  PaymentItem item1;
+  PaymentItem item2;
+  EXPECT_EQ(item1, item2);
+
+  item1.label = base::ASCIIToUTF16("Subtotal");
+  EXPECT_NE(item1, item2);
+  item2.label = base::ASCIIToUTF16("Total");
+  EXPECT_NE(item1, item2);
+  item2.label = base::ASCIIToUTF16("Subtotal");
+  EXPECT_EQ(item1, item2);
+
+  item1.amount.value = base::ASCIIToUTF16("104.34");
+  EXPECT_NE(item1, item2);
+  item2.amount.value = base::ASCIIToUTF16("104");
+  EXPECT_NE(item1, item2);
+  item2.amount.value = base::ASCIIToUTF16("104.34");
+  EXPECT_EQ(item1, item2);
+
+  item1.pending = true;
+  EXPECT_NE(item1, item2);
+  item2.pending = true;
+  EXPECT_EQ(item1, item2);
+}
+
+// Tests that serializing a default PaymentItem yields the expected result.
+TEST(PaymentRequestTest, EmptyPaymentItemDictionary) {
+  base::DictionaryValue expected_value;
+
+  expected_value.SetString("label", "");
+  std::unique_ptr<base::DictionaryValue> amount_dict =
+      base::MakeUnique<base::DictionaryValue>();
+  amount_dict->SetString("currency", "");
+  amount_dict->SetString("value", "");
+  amount_dict->SetString("currencySystem", "urn:iso:std:iso:4217");
+  expected_value.SetDictionary("amount", std::move(amount_dict));
+  expected_value.SetBoolean("pending", false);
+
+  PaymentItem payment_item;
+  EXPECT_TRUE(expected_value.Equals(payment_item.ToDictionaryValue().get()));
+}
+
+// Tests that serializing a populated PaymentItem yields the expected result.
+TEST(PaymentRequestTest, PopulatedPaymentItemDictionary) {
+  base::DictionaryValue expected_value;
+
+  expected_value.SetString("label", "Payment Total");
+  std::unique_ptr<base::DictionaryValue> amount_dict =
+      base::MakeUnique<base::DictionaryValue>();
+  amount_dict->SetString("currency", "NZD");
+  amount_dict->SetString("value", "2,242,093.00");
+  amount_dict->SetString("currencySystem", "urn:iso:std:iso:4217");
+  expected_value.SetDictionary("amount", std::move(amount_dict));
+  expected_value.SetBoolean("pending", true);
+
+  PaymentItem payment_item;
+  payment_item.label = base::ASCIIToUTF16("Payment Total");
+  payment_item.amount.currency = base::ASCIIToUTF16("NZD");
+  payment_item.amount.value = base::ASCIIToUTF16("2,242,093.00");
+  payment_item.pending = true;
+
+  EXPECT_TRUE(expected_value.Equals(payment_item.ToDictionaryValue().get()));
+}
+
+}  // namespace payments
diff --git a/components/payments/core/payment_shipping_option.cc b/components/payments/core/payment_shipping_option.cc
new file mode 100644
index 0000000..5e91a4b44
--- /dev/null
+++ b/components/payments/core/payment_shipping_option.cc
@@ -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.
+
+#include "components/payments/core/payment_shipping_option.h"
+
+#include "base/values.h"
+
+namespace payments {
+
+namespace {
+
+// These are defined as part of the spec at:
+// https://w3c.github.io/browser-payment-api/#dom-paymentshippingoption
+static const char kPaymentShippingOptionAmount[] = "amount";
+static const char kPaymentShippingOptionId[] = "id";
+static const char kPaymentShippingOptionLabel[] = "label";
+static const char kPaymentShippingOptionSelected[] = "selected";
+
+}  // namespace
+
+PaymentShippingOption::PaymentShippingOption() : selected(false) {}
+PaymentShippingOption::PaymentShippingOption(
+    const PaymentShippingOption& other) = default;
+PaymentShippingOption::~PaymentShippingOption() = default;
+
+bool PaymentShippingOption::operator==(
+    const PaymentShippingOption& other) const {
+  return this->id == other.id && this->label == other.label &&
+         this->amount == other.amount && this->selected == other.selected;
+}
+
+bool PaymentShippingOption::operator!=(
+    const PaymentShippingOption& other) const {
+  return !(*this == other);
+}
+
+bool PaymentShippingOption::FromDictionaryValue(
+    const base::DictionaryValue& value) {
+  if (!value.GetString(kPaymentShippingOptionId, &this->id)) {
+    return false;
+  }
+
+  if (!value.GetString(kPaymentShippingOptionLabel, &this->label)) {
+    return false;
+  }
+
+  const base::DictionaryValue* amount_dict = nullptr;
+  if (!value.GetDictionary(kPaymentShippingOptionAmount, &amount_dict)) {
+    return false;
+  }
+  if (!this->amount.FromDictionaryValue(*amount_dict)) {
+    return false;
+  }
+
+  // Selected is optional.
+  value.GetBoolean(kPaymentShippingOptionSelected, &this->selected);
+
+  return true;
+}
+
+}  // namespace payments
diff --git a/components/payments/core/payment_shipping_option.h b/components/payments/core/payment_shipping_option.h
new file mode 100644
index 0000000..def7b53a
--- /dev/null
+++ b/components/payments/core/payment_shipping_option.h
@@ -0,0 +1,54 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_PAYMENTS_CORE_PAYMENT_SHIPPING_OPTION_H_
+#define COMPONENTS_PAYMENTS_CORE_PAYMENT_SHIPPING_OPTION_H_
+
+#include "base/strings/string16.h"
+#include "components/payments/core/payment_currency_amount.h"
+
+// C++ bindings for the PaymentRequest API PaymentShippingOption. Conforms to
+// the following spec:
+// https://w3c.github.io/browser-payment-api/#dom-paymentshippingoption
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace payments {
+
+// Information describing a shipping option.
+class PaymentShippingOption {
+ public:
+  PaymentShippingOption();
+  PaymentShippingOption(const PaymentShippingOption& other);
+  ~PaymentShippingOption();
+
+  bool operator==(const PaymentShippingOption& other) const;
+  bool operator!=(const PaymentShippingOption& other) const;
+
+  // Populates the properties of this PaymentShippingOption from |value|.
+  // Returns true if the required values are present.
+  bool FromDictionaryValue(const base::DictionaryValue& value);
+
+  // An identifier used to reference this PaymentShippingOption. It is unique
+  // for a given PaymentRequest.
+  base::string16 id;
+
+  // A human-readable description of the item. The user agent should use this
+  // string to display the shipping option to the user.
+  base::string16 label;
+
+  // A PaymentCurrencyAmount containing the monetary amount for the option.
+  PaymentCurrencyAmount amount;
+
+  // This is set to true to indicate that this is the default selected
+  // PaymentShippingOption in a sequence. User agents should display this option
+  // by default in the user interface.
+  bool selected;
+};
+
+}  // namespace payments
+
+#endif  // COMPONENTS_PAYMENTS_CORE_PAYMENT_SHIPPING_OPTION_H_
diff --git a/components/payments/core/payment_shipping_option_unittest.cc b/components/payments/core/payment_shipping_option_unittest.cc
new file mode 100644
index 0000000..ea423d79
--- /dev/null
+++ b/components/payments/core/payment_shipping_option_unittest.cc
@@ -0,0 +1,110 @@
+// 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/payments/core/payment_shipping_option.h"
+
+#include <memory>
+
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace payments {
+
+// Tests the success case when populating a PaymentShippingOption from a
+// dictionary.
+TEST(PaymentRequestTest, PaymentShippingOptionFromDictionaryValueSuccess) {
+  PaymentShippingOption expected;
+  expected.id = base::ASCIIToUTF16("123");
+  expected.label = base::ASCIIToUTF16("Ground Shipping");
+  expected.amount.currency = base::ASCIIToUTF16("BRL");
+  expected.amount.value = base::ASCIIToUTF16("4,000.32");
+  expected.selected = true;
+
+  base::DictionaryValue shipping_option_dict;
+  shipping_option_dict.SetString("id", "123");
+  shipping_option_dict.SetString("label", "Ground Shipping");
+  std::unique_ptr<base::DictionaryValue> amount_dict(new base::DictionaryValue);
+  amount_dict->SetString("currency", "BRL");
+  amount_dict->SetString("value", "4,000.32");
+  shipping_option_dict.Set("amount", std::move(amount_dict));
+  shipping_option_dict.SetBoolean("selected", true);
+
+  PaymentShippingOption actual;
+  EXPECT_TRUE(actual.FromDictionaryValue(shipping_option_dict));
+
+  EXPECT_EQ(expected, actual);
+}
+
+// Tests the failure case when populating a PaymentShippingOption from a
+// dictionary.
+TEST(PaymentRequestTest, PaymentShippingOptionFromDictionaryValueFailure) {
+  PaymentShippingOption expected;
+  expected.id = base::ASCIIToUTF16("123");
+  expected.label = base::ASCIIToUTF16("Ground Shipping");
+  expected.amount.currency = base::ASCIIToUTF16("BRL");
+  expected.amount.value = base::ASCIIToUTF16("4,000.32");
+  expected.selected = true;
+
+  PaymentShippingOption actual;
+  base::DictionaryValue shipping_option_dict;
+
+  // Id, Label, and amount are required.
+  shipping_option_dict.SetString("id", "123");
+  EXPECT_FALSE(actual.FromDictionaryValue(shipping_option_dict));
+
+  shipping_option_dict.SetString("label", "Ground Shipping");
+  EXPECT_FALSE(actual.FromDictionaryValue(shipping_option_dict));
+
+  // Id must be a string.
+  std::unique_ptr<base::DictionaryValue> amount_dict(new base::DictionaryValue);
+  amount_dict->SetString("currency", "BRL");
+  amount_dict->SetString("value", "4,000.32");
+  shipping_option_dict.Set("amount", std::move(amount_dict));
+  shipping_option_dict.SetInteger("id", 123);
+  EXPECT_FALSE(actual.FromDictionaryValue(shipping_option_dict));
+
+  // Label must be a string.
+  shipping_option_dict.SetString("id", "123");
+  shipping_option_dict.SetInteger("label", 123);
+  EXPECT_FALSE(actual.FromDictionaryValue(shipping_option_dict));
+}
+
+// Tests that two shipping option objects are not equal if their property values
+// differ or one is missing a value present in the other, and equal otherwise.
+// Doesn't test all properties of child objects, relying instead on their
+// respective tests.
+TEST(PaymentRequestTest, PaymentShippingOptionEquality) {
+  PaymentShippingOption shipping_option1;
+  PaymentShippingOption shipping_option2;
+  EXPECT_EQ(shipping_option1, shipping_option2);
+
+  shipping_option1.id = base::ASCIIToUTF16("a8df2");
+  EXPECT_NE(shipping_option1, shipping_option2);
+  shipping_option2.id = base::ASCIIToUTF16("k42jk");
+  EXPECT_NE(shipping_option1, shipping_option2);
+  shipping_option2.id = base::ASCIIToUTF16("a8df2");
+  EXPECT_EQ(shipping_option1, shipping_option2);
+
+  shipping_option1.label = base::ASCIIToUTF16("Overnight");
+  EXPECT_NE(shipping_option1, shipping_option2);
+  shipping_option2.label = base::ASCIIToUTF16("Ground");
+  EXPECT_NE(shipping_option1, shipping_option2);
+  shipping_option2.label = base::ASCIIToUTF16("Overnight");
+  EXPECT_EQ(shipping_option1, shipping_option2);
+
+  shipping_option1.amount.currency = base::ASCIIToUTF16("AUD");
+  EXPECT_NE(shipping_option1, shipping_option2);
+  shipping_option2.amount.currency = base::ASCIIToUTF16("HKD");
+  EXPECT_NE(shipping_option1, shipping_option2);
+  shipping_option2.amount.currency = base::ASCIIToUTF16("AUD");
+  EXPECT_EQ(shipping_option1, shipping_option2);
+
+  shipping_option1.selected = true;
+  EXPECT_NE(shipping_option1, shipping_option2);
+  shipping_option2.selected = true;
+  EXPECT_EQ(shipping_option1, shipping_option2);
+}
+
+}  // namespace payments
diff --git a/components/proximity_auth/proximity_auth_system_unittest.cc b/components/proximity_auth/proximity_auth_system_unittest.cc
index 4a4428b4..9ef1c79 100644
--- a/components/proximity_auth/proximity_auth_system_unittest.cc
+++ b/components/proximity_auth/proximity_auth_system_unittest.cc
@@ -55,7 +55,8 @@
 RemoteDevice CreateRemoteDevice(const std::string& user_id,
                                 const std::string& name) {
   return RemoteDevice(user_id, name + "_pk", name, name + "_btaddr",
-                      name + "_psk", name + "_challenge");
+                      name + "_psk", true /* unlock_key */,
+                      true /* supports_mobile_hotspot */);
 }
 
 // Mock implementation of UnlockManager.
diff --git a/components/proximity_auth/proximity_monitor_impl_unittest.cc b/components/proximity_auth/proximity_monitor_impl_unittest.cc
index ce59377..60602f685 100644
--- a/components/proximity_auth/proximity_monitor_impl_unittest.cc
+++ b/components/proximity_auth/proximity_monitor_impl_unittest.cc
@@ -97,7 +97,8 @@
                        kRemoteDevicePublicKey,
                        kBluetoothAddress,
                        kPersistentSymmetricKey,
-                       std::string()),
+                       true /* unlock_key */,
+                       true /* mobile_hotspot_supported */),
         connection_(remote_device_),
         pref_manager_(new NiceMock<MockProximityAuthPrefManager>()),
         monitor_(&connection_, base::WrapUnique(clock_), pref_manager_.get()),
@@ -362,7 +363,8 @@
   // Note: A device without a recorded name will have "Unknown" as its name.
   cryptauth::RemoteDevice unnamed_remote_device(
       kRemoteDeviceUserId, "" /* name */, kRemoteDevicePublicKey,
-      kBluetoothAddress, kPersistentSymmetricKey, std::string());
+      kBluetoothAddress, kPersistentSymmetricKey, true /* unlock_key */,
+      true /* supports_mobile_hotspot */);
   cryptauth::FakeConnection connection(unnamed_remote_device);
 
   std::unique_ptr<base::TickClock> clock(new base::SimpleTestTickClock());
diff --git a/components/proximity_auth/webui/resources/pollux.html b/components/proximity_auth/webui/resources/pollux.html
index 256d8448..4897009 100644
--- a/components/proximity_auth/webui/resources/pollux.html
+++ b/components/proximity_auth/webui/resources/pollux.html
@@ -27,7 +27,7 @@
         <div class='control-title'>SERVER</div>
         <div class='control-row'>
           <div class='control-row-text'>MASTER_KEY:</div>
-          <input class='textinput' type='text' value='F3DA234A14'></input>
+          <input class='textinput' type='text' value='F3DA234A14'>
         </div>
         <div class='control-row'><button>Challenge</button></div>
       </div>
@@ -37,15 +37,15 @@
         <div class='control-title'>GET ASSERTION</div>
         <div class='control-row'>
           <div class='control-row-text'>CHALLENGE:</div>
-          <input class='textinput' type='text' value='A3DA234A14'></input>
+          <input class='textinput' type='text' value='A3DA234A14'>
         </div>
         <div class='control-row'>
           <div class='control-row-text'>EID:</div>
-          <input class='textinput' type='text' value='A3DA234A14'></input>
+          <input class='textinput' type='text' value='A3DA234A14'>
         </div>
         <div class='control-row'>
           <div class='control-row-text'>SESSION_KEY:</div>
-          <input class='textinput' type='text' value='A3DA234A14'></input>
+          <input class='textinput' type='text' value='A3DA234A14'>
         </div>
         <div class='control-row'><button>Start</button></div>
       </div>
diff --git a/components/search_engines/prepopulated_engines.json b/components/search_engines/prepopulated_engines.json
index 02999b5..212a816 100644
--- a/components/search_engines/prepopulated_engines.json
+++ b/components/search_engines/prepopulated_engines.json
@@ -146,7 +146,7 @@
       "name": "@MAIL.RU",
       "keyword": "mail.ru",
       "favicon_url": "https://go.imgsmail.ru/favicon.ico",
-      "search_url": "https://go.mail.ru/search?q={searchTerms}",
+      "search_url": "https://go.mail.ru/search?q={searchTerms}&{mailru:referralID}",
       "encoding": "windows-1251",
       "suggest_url": "https://suggests.go.mail.ru/chrome?q={searchTerms}",
       "type": "SEARCH_ENGINE_MAILRU",
diff --git a/components/search_engines/search_terms_data.cc b/components/search_engines/search_terms_data.cc
index d532ae6..a976227 100644
--- a/components/search_engines/search_terms_data.cc
+++ b/components/search_engines/search_terms_data.cc
@@ -70,3 +70,7 @@
 std::string SearchTermsData::GetYandexReferralID() const {
   return std::string();
 }
+
+std::string SearchTermsData::GetMailRUReferralID() const {
+  return std::string();
+}
diff --git a/components/search_engines/search_terms_data.h b/components/search_engines/search_terms_data.h
index c72b992..302c906 100644
--- a/components/search_engines/search_terms_data.h
+++ b/components/search_engines/search_terms_data.h
@@ -65,6 +65,10 @@
   // the omnibox (returns the empty string if not supported/applicable).
   virtual std::string GetYandexReferralID() const;
 
+  // Returns the optional referral ID to be passed to @MAIL.RU when searching
+  // from the omnibox (returns the empty string if not supported/applicable).
+  virtual std::string GetMailRUReferralID() const;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(SearchTermsData);
 };
diff --git a/components/search_engines/template_url.cc b/components/search_engines/template_url.cc
index 1478d89..0316dd8 100644
--- a/components/search_engines/template_url.cc
+++ b/components/search_engines/template_url.cc
@@ -659,6 +659,8 @@
     replacements->push_back(Replacement(GOOGLE_UNESCAPED_SEARCH_TERMS, start));
   } else if (parameter == "yandex:referralID") {
     replacements->push_back(Replacement(YANDEX_REFERRAL_ID, start));
+  } else if (parameter == "mailru:referralID") {
+    replacements->push_back(Replacement(MAIL_RU_REFERRAL_ID, start));
   } else if (parameter == "yandex:searchPath") {
     switch (ui::GetDeviceFormFactor()) {
       case ui::DEVICE_FORM_FACTOR_DESKTOP:
@@ -1141,6 +1143,13 @@
         break;
       }
 
+      case MAIL_RU_REFERRAL_ID: {
+        std::string referral_id = search_terms_data.GetMailRUReferralID();
+        if (!referral_id.empty())
+          HandleReplacement("gp", referral_id, *i, &url);
+        break;
+      }
+
       default:
         NOTREACHED();
         break;
diff --git a/components/search_engines/template_url.h b/components/search_engines/template_url.h
index 838f169..e5cb8df5 100644
--- a/components/search_engines/template_url.h
+++ b/components/search_engines/template_url.h
@@ -326,6 +326,7 @@
     GOOGLE_SUGGEST_REQUEST_ID,
     GOOGLE_UNESCAPED_SEARCH_TERMS,
     LANGUAGE,
+    MAIL_RU_REFERRAL_ID,
     SEARCH_TERMS,
     YANDEX_REFERRAL_ID,
   };
diff --git a/components/security_interstitials/core/browser/resources/list_of_interstitials.html b/components/security_interstitials/core/browser/resources/list_of_interstitials.html
index d9a13f8b..639d6769 100644
--- a/components/security_interstitials/core/browser/resources/list_of_interstitials.html
+++ b/components/security_interstitials/core/browser/resources/list_of_interstitials.html
@@ -46,6 +46,12 @@
     <li>
       <a href="superfish-ssl">Superfish</a>
     </li>
+    <li>
+      <a href="mitm-software-ssl?enterprise=0">MITM software</a>
+    </li>
+    <li>
+      <a href="mitm-software-ssl?enterprise=1">MITM software on an enterprise-managed machine</a>
+    </li>
   </ul>
   <h3>SafeBrowsing</h3>
   <h4>Loud</h4>
diff --git a/components/security_interstitials/core/mitm_software_ui.cc b/components/security_interstitials/core/mitm_software_ui.cc
index 8724098..f15cf8a 100644
--- a/components/security_interstitials/core/mitm_software_ui.cc
+++ b/components/security_interstitials/core/mitm_software_ui.cc
@@ -37,7 +37,6 @@
   controller_->metrics_helper()->RecordShutdownMetrics();
 }
 
-// TODO(sperigo): Fill in placeholder strings.
 void MITMSoftwareUI::PopulateStringsForHTML(
     base::DictionaryValue* load_time_data) {
   CHECK(load_time_data);
@@ -116,7 +115,8 @@
       "explanationParagraph",
       l10n_util::GetStringFUTF16(
           IDS_MITM_SOFTWARE_EXPLANATION_ENTERPRISE,
-          net::EscapeForHTML(base::UTF8ToUTF16(mitm_software_name_))));
+          net::EscapeForHTML(base::UTF8ToUTF16(mitm_software_name_)),
+          l10n_util::GetStringUTF16(IDS_MITM_SOFTWARE_EXPLANATION)));
 }
 
 void MITMSoftwareUI::PopulateAtHomeUserStringsForHTML(
@@ -130,7 +130,8 @@
       "explanationParagraph",
       l10n_util::GetStringFUTF16(
           IDS_MITM_SOFTWARE_EXPLANATION_NONENTERPRISE,
-          net::EscapeForHTML(base::UTF8ToUTF16(mitm_software_name_))));
+          net::EscapeForHTML(base::UTF8ToUTF16(mitm_software_name_)),
+          l10n_util::GetStringUTF16(IDS_MITM_SOFTWARE_EXPLANATION)));
 }
 
 }  // namespace security_interstitials
diff --git a/components/security_interstitials_strings.grdp b/components/security_interstitials_strings.grdp
index 8ad2b8c..e5fee889 100644
--- a/components/security_interstitials_strings.grdp
+++ b/components/security_interstitials_strings.grdp
@@ -41,24 +41,27 @@
   </message>
 
   <!-- MITM software interstitial -->
-  <message name="IDS_MITM_SOFTWARE_HEADING" desc="Heading of the error page for SSL errors triggered by misconfigured MITM software">
+  <message name="IDS_MITM_SOFTWARE_HEADING" desc="Header of an error page. A user visits a website, antivirus or firewall software interferes with their connection, and they are shown this error.">
     An application is stopping Chrome from safely connecting to this site
   </message>
-  <message name="IDS_MITM_SOFTWARE_PRIMARY_PARAGRAPH_ENTERPRISE" desc="Primary explanatory paragraph for the MITM software error page shown to enterprise users">
-    &quot;<ph name="SOFTWARE_NAME">$1<ex>Misconfigured Antivirus</ex></ph>&quot; wasn’t installed properly on your computer or network. Ask your administrator to resolve this issue.
+  <message name="IDS_MITM_SOFTWARE_PRIMARY_PARAGRAPH_ENTERPRISE" desc="Main body of an error page. A user visits a website, antivirus or firewall software interferes with their connection, and they are shown this error. There is a title above and a button below that exposes more information. ‘IT administrator’ here refers to the information technology expert at the user’s school or company. Placeholder text is the name of a computer program.">
+    &quot;<ph name="SOFTWARE_NAME">$1<ex>Misconfigured Antivirus</ex></ph>&quot; wasn’t installed properly on your computer or network. Ask your IT administrator to resolve this issue.
   </message>
-  <message name="IDS_MITM_SOFTWARE_PRIMARY_PARAGRAPH_NONENTERPRISE" desc="Primary explanatory paragraph for the MITM software error page shown to non-enterprise users">
+  <message name="IDS_MITM_SOFTWARE_PRIMARY_PARAGRAPH_NONENTERPRISE" desc="Main body of an error page. A user visits a website, antivirus or firewall software interferes with their connection, and they are shown this error. There is a title above and a button below that exposes more information. Placeholder text is the name of a computer program.">
     &quot;<ph name="SOFTWARE_NAME">$1<ex>Misconfigured Antivirus</ex></ph>&quot; wasn’t installed properly on your computer or the network:
     &lt;ul&gt;
-    &lt;li&gt;Try uninstalling &quot;<ph name="SOFTWARE_NAME">$1<ex>Misconfigured Antivirus</ex></ph>&quot;&lt;/li&gt;
-    &lt;li&gt;Try connecting to another Wi-Fi network&lt;/li&gt;
+    &lt;li&gt;Try uninstalling or disabling &quot;<ph name="SOFTWARE_NAME">$1<ex>Misconfigured Antivirus</ex></ph>&quot;&lt;/li&gt;
+    &lt;li&gt;Try connecting to another network&lt;/li&gt;
     &lt;/ul&gt;
   </message>
-  <message name="IDS_MITM_SOFTWARE_EXPLANATION_ENTERPRISE" desc="Body text under the 'Advanced' button for the MITM software error page shown to enterprise users. Provides more context about the error and offers solutions aimed at the network administrator.">
-    A root certificate for &quot;<ph name="SOFTWARE_NAME">$1<ex>Misconfigured Antivirus</ex></ph>&quot; is required but isn’t installed. Your network administrator should look at configuration instructions for &quot;<ph name="SOFTWARE_NAME">$1<ex>Misconfigured Antivirus</ex></ph>&quot; to fix this problem. Applications that can cause this error includes antivirus, firewall, and web-filtering or proxy software.
+  <message name="IDS_MITM_SOFTWARE_EXPLANATION_ENTERPRISE" desc="Extended description for an error page hidden behind an 'Advanced' button. A user visits a website, antivirus or firewall software interferes with their connection, and they are shown this error. Page title reads 'An application is stopping Chrome from safely connection to this site' and there is a shorter description of the error shown above. First placeholder text is the name of a computer program. Second placeholder text is some further explanation.">
+    A root certificate for &quot;<ph name="SOFTWARE_NAME">$1<ex>Misconfigured Antivirus</ex></ph>&quot; is required but isn’t installed. Your IT administrator should look at configuration instructions for &quot;<ph name="SOFTWARE_NAME">$1<ex>Misconfigured Antivirus</ex></ph>&quot; to fix this problem. <ph name="FURTHER_EXPLANATION">$2<ex>Futher explanation goes here.</ex></ph>
   </message>
-  <message name="IDS_MITM_SOFTWARE_EXPLANATION_NONENTERPRISE" desc="Body text under the 'Advanced' button for the MITM software error page shown to enterprise users. Provides more context about the error.">
-    &quot;<ph name="SOFTWARE_NAME">$1<ex>Misconfigured Antivirus</ex></ph>&quot; isn’t configured correctly. Uninstalling &quot;<ph name="SOFTWARE_NAME">$1<ex>Misconfigured Antivirus</ex></ph>&quot; usually fixes the problem. Applications that can cause this error includes antivirus, firewall, and web-filtering or proxy software.
+  <message name="IDS_MITM_SOFTWARE_EXPLANATION_NONENTERPRISE" desc="Extended description for an error page hidden behind an 'Advanced' button. A user visits a website, antivirus or firewall software interferes with their connection, and they are shown this error. Page title reads 'An application is stopping Chrome from safely connection to this site' and there is a shorter description of the error shown above. First placeholder text is the name of a computer program. Second placeholder text is some further explanation.">
+    &quot;<ph name="SOFTWARE_NAME">$1<ex>Misconfigured Antivirus</ex></ph>&quot; isn’t configured correctly. Uninstalling &quot;<ph name="SOFTWARE_NAME">$1<ex>Misconfigured Antivirus</ex></ph>&quot; usually fixes the problem. <ph name="FURTHER_EXPLANATION">$2<ex>Futher explanation goes here.</ex></ph>
+  </message>
+  <message name="IDS_MITM_SOFTWARE_EXPLANATION" desc="Part of an extended description hidden behind an 'Advanced' button on an error page. A user visits a website, antivirus or firewall software interferes with their connection, and they are shown this error. Page title and additional description of the error are shown above. 'Antivirus software' is software that finds and deletes viruses on a user's computer. 'Firewall software' is software typically used on a company network that keeps unwanted people from accessing the network. 'Proxy software' is software on a network that blocks the user from viewing certain websites. Proxies may be used to keep school children from viewing inappropriate websites for example. 'Web-filtering software' is a synonym for proxy software, so it can be excluded in translation.">
+    Applications that can cause this error includes antivirus, firewall, and web-filtering or proxy software.
   </message>
 
   <!-- Clock errors -->
diff --git a/components/session_manager/session_manager_types.h b/components/session_manager/session_manager_types.h
index 5a88b4e7..f38650a9 100644
--- a/components/session_manager/session_manager_types.h
+++ b/components/session_manager/session_manager_types.h
@@ -48,8 +48,10 @@
   AccountId user_account_id;
 };
 
-// Limits the number of logged in users to 10 due to memory constraints.
-constexpr int kMaxmiumNumberOfUserSessions = 10;
+// Limits the number of logged in users to 5. User-switcher UI was not designed
+// around a large number of users. This also helps on memory-constrained
+// devices. See b/64593342 for some additional context.
+constexpr int kMaximumNumberOfUserSessions = 5;
 
 }  // namespace session_manager
 
diff --git a/components/sync/driver/resources/about.html b/components/sync/driver/resources/about.html
index ca91424..d0ffbae 100644
--- a/components/sync/driver/resources/about.html
+++ b/components/sync/driver/resources/about.html
@@ -1,10 +1,8 @@
-
 <div id="status">
   <div id="dump">
     <button id="dump-status">Dump status</button>
     <input type="checkbox" id="include-ids">
-      Include Identifiers
-    </input>
+    Include Identifiers
   </div>
   <div id="import">
     <button id="import-status">Import status</button>
@@ -29,7 +27,7 @@
 
   <div id="traffic-event-container-wrapper" jsskip="true">
     <h2 style="display:inline-block">Sync Protocol Log</h2>
-    <input type="checkbox" id="capture-specifics"></input>
+    <input type="checkbox" id="capture-specifics">
     <label for="capture-specifics">Capture Specifics</label>
     <div id="traffic-event-container">
       <div class="traffic-event-entry"
diff --git a/components/ukm/ukm_source.cc b/components/ukm/ukm_source.cc
index c9eda12..5324048 100644
--- a/components/ukm/ukm_source.cc
+++ b/components/ukm/ukm_source.cc
@@ -4,6 +4,7 @@
 
 #include "components/ukm/ukm_source.h"
 
+#include "base/atomicops.h"
 #include "base/hash.h"
 #include "components/metrics/proto/ukm/source.pb.h"
 
@@ -17,6 +18,12 @@
 // The string sent in place of a URL if the real URL was too long.
 constexpr char kMaxUrlLengthMessage[] = "URLTooLong";
 
+// Using a simple global assumes that all access to it will be done on the same
+// thread, namely the UI thread. If this becomes not the case then it can be
+// changed to an Atomic32 (make CustomTabState derive from int32_t) and accessed
+// with no-barrier loads and stores.
+UkmSource::CustomTabState g_custom_tab_state = UkmSource::kCustomTabUnset;
+
 // Returns a URL that is under the length limit, by returning a constant
 // string when the URl is too long.
 std::string GetShortenedURL(const GURL& url) {
@@ -27,7 +34,12 @@
 
 }  // namespace
 
-UkmSource::UkmSource() = default;
+// static
+void UkmSource::SetCustomTabVisible(bool visible) {
+  g_custom_tab_state = visible ? kCustomTabTrue : kCustomTabFalse;
+}
+
+UkmSource::UkmSource() : custom_tab_state_(g_custom_tab_state) {}
 
 UkmSource::~UkmSource() = default;
 
@@ -49,6 +61,9 @@
   proto_source->set_url(GetShortenedURL(url_));
   if (!initial_url_.is_empty())
     proto_source->set_initial_url(GetShortenedURL(initial_url_));
+
+  if (custom_tab_state_ != kCustomTabUnset)
+    proto_source->set_is_custom_tab(custom_tab_state_ == kCustomTabTrue);
 }
 
 }  // namespace ukm
diff --git a/components/ukm/ukm_source.h b/components/ukm/ukm_source.h
index 307eda3..6492cd1c 100644
--- a/components/ukm/ukm_source.h
+++ b/components/ukm/ukm_source.h
@@ -9,6 +9,7 @@
 
 #include "base/macros.h"
 #include "base/time/time.h"
+#include "build/build_config.h"
 #include "services/metrics/public/cpp/ukm_source_id.h"
 #include "url/gurl.h"
 
@@ -19,6 +20,12 @@
 // Contains UKM data for a single navigation entry.
 class UkmSource {
  public:
+  enum CustomTabState {
+    kCustomTabUnset,
+    kCustomTabTrue,
+    kCustomTabFalse,
+  };
+
   UkmSource();
   ~UkmSource();
 
@@ -41,6 +48,9 @@
   // Serializes the members of the class into the supplied proto.
   void PopulateProto(Source* proto_source) const;
 
+  // Sets the current "custom tab" state. This can be called from any thread.
+  static void SetCustomTabVisible(bool visible);
+
  private:
   ukm::SourceId id_;
 
@@ -51,6 +61,11 @@
   // the URL changed over the lifetime of this source).
   GURL initial_url_;
 
+  // A flag indicating if metric was collected in a custom tab. This is set
+  // automatically when the object is created and so represents the state when
+  // the metric was created.
+  const CustomTabState custom_tab_state_;
+
   DISALLOW_COPY_AND_ASSIGN(UkmSource);
 };
 
diff --git a/components/vector_icons/BUILD.gn b/components/vector_icons/BUILD.gn
index 1b8d75b4..b03c189 100644
--- a/components/vector_icons/BUILD.gn
+++ b/components/vector_icons/BUILD.gn
@@ -8,6 +8,7 @@
   icon_directory = "."
 
   icons = [
+    "accessibility.icon",
     "back_arrow.1x.icon",
     "back_arrow.icon",
     "bluetooth_connected.icon",
diff --git a/components/vector_icons/accessibility.icon b/components/vector_icons/accessibility.icon
new file mode 100644
index 0000000..62b8b71c
--- /dev/null
+++ b/components/vector_icons/accessibility.icon
@@ -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.
+
+CANVAS_DIMENSIONS, 32,
+MOVE_TO, 16, 11.44f,
+R_CUBIC_TO, -3.5f, 0, -7.2f, -0.62f, -10.27f, -1.44f,
+LINE_TO, 5, 12.16f,
+R_CUBIC_TO, 2.27f, 0.77f, 5.56f, 1.05f, 8, 1.34f,
+V_LINE_TO, 28,
+R_H_LINE_TO, 2,
+R_V_LINE_TO, -7,
+R_H_LINE_TO, 2,
+R_V_LINE_TO, 7,
+R_H_LINE_TO, 2,
+V_LINE_TO, 13.5f,
+R_CUBIC_TO, 2.44f, -0.29f, 5.73f, -0.57f, 8, -1.34f,
+LINE_TO, 26.27f, 10,
+R_CUBIC_TO, -3.07f, 0.82f, -6.77f, 1.44f, -10.27f, 1.44f,
+CLOSE,
+R_MOVE_TO, 0, -1.94f,
+R_ARC_TO, 2.5f, 2.5f, 0, 1, 0, 0, -5,
+R_ARC_TO, 2.5f, 2.5f, 0, 0, 0, 0, 5,
+CLOSE,
+END
diff --git a/components/viz/service/display_embedder/compositor_overlay_candidate_validator_ozone.cc b/components/viz/service/display_embedder/compositor_overlay_candidate_validator_ozone.cc
index de5ec40..8486107 100644
--- a/components/viz/service/display_embedder/compositor_overlay_candidate_validator_ozone.cc
+++ b/components/viz/service/display_embedder/compositor_overlay_candidate_validator_ozone.cc
@@ -102,8 +102,6 @@
     ozone_surface_list.at(i).format = surfaces->at(i).format;
     ozone_surface_list.at(i).display_rect = surfaces->at(i).display_rect;
     ozone_surface_list.at(i).crop_rect = surfaces->at(i).uv_rect;
-    ozone_surface_list.at(i).quad_rect_in_target_space =
-        surfaces->at(i).quad_rect_in_target_space;
     ozone_surface_list.at(i).clip_rect = surfaces->at(i).clip_rect;
     ozone_surface_list.at(i).is_clipped = surfaces->at(i).is_clipped;
     ozone_surface_list.at(i).plane_z_order = surfaces->at(i).plane_z_order;
diff --git a/components/viz/service/hit_test/hit_test_aggregator.cc b/components/viz/service/hit_test/hit_test_aggregator.cc
index 4b07ea15..30390725 100644
--- a/components/viz/service/hit_test/hit_test_aggregator.cc
+++ b/components/viz/service/hit_test/hit_test_aggregator.cc
@@ -18,8 +18,9 @@
 constexpr uint32_t kMaxSize = 100 * 1024;
 
 bool ValidateHitTestRegion(const mojom::HitTestRegionPtr& hit_test_region) {
-  if (hit_test_region->flags == mojom::kHitTestChildSurface) {
-    if (!hit_test_region->surface_id.is_valid())
+  if (hit_test_region->flags & mojom::kHitTestChildSurface) {
+    if (!hit_test_region->local_surface_id.has_value() ||
+        !hit_test_region->local_surface_id->is_valid())
       return false;
   }
 
@@ -193,7 +194,7 @@
                                        const mojom::HitTestRegionPtr& region) {
   AggregatedHitTestRegion* element = &regions[region_index];
 
-  element->frame_sink_id = region->surface_id.frame_sink_id();
+  element->frame_sink_id = region->frame_sink_id;
   element->flags = region->flags;
   element->rect = region->rect;
   element->transform = region->transform;
@@ -204,8 +205,10 @@
     return region_index;
   }
 
-  if (region->flags == mojom::kHitTestChildSurface) {
-    auto search = active_.find(region->surface_id);
+  if (region->flags & mojom::kHitTestChildSurface) {
+    auto surface_id =
+        SurfaceId(region->frame_sink_id, region->local_surface_id.value());
+    auto search = active_.find(surface_id);
     if (search == active_.end()) {
       // Surface HitTestRegionList not found - it may be late.
       // Don't include this region so that it doesn't receive events.
diff --git a/components/viz/service/hit_test/hit_test_aggregator_unittest.cc b/components/viz/service/hit_test/hit_test_aggregator_unittest.cc
index c52abcb..0a45639 100644
--- a/components/viz/service/hit_test/hit_test_aggregator_unittest.cc
+++ b/components/viz/service/hit_test/hit_test_aggregator_unittest.cc
@@ -238,10 +238,12 @@
     for (int i = 0; i < 8; i++) {
       auto hit_test_region = mojom::HitTestRegion::New();
       hit_test_region->rect.SetRect(100, 100, 100, 100);
+      SurfaceId child_surface_id = MakeSurfaceId(kDisplayFrameSink, id);
+      hit_test_region->frame_sink_id = child_surface_id.frame_sink_id();
+      hit_test_region->local_surface_id = child_surface_id.local_surface_id();
 
       if (depth > 0) {
         hit_test_region->flags = mojom::kHitTestChildSurface;
-        hit_test_region->surface_id = MakeSurfaceId(kDisplayFrameSink, id);
         id = CreateAndSubmitHitTestRegionListWith8Children(id, depth - 1);
       } else {
         hit_test_region->flags = mojom::kHitTestMine;
@@ -349,12 +351,14 @@
   e_hit_test_region_list->bounds.SetRect(0, 0, 1024, 768);
 
   auto e_hit_test_region_r1 = mojom::HitTestRegion::New();
-  e_hit_test_region_r1->surface_id = e_surface_id;
+  e_hit_test_region_r1->frame_sink_id = e_surface_id.frame_sink_id();
+  e_hit_test_region_r1->local_surface_id = e_surface_id.local_surface_id();
   e_hit_test_region_r1->flags = mojom::kHitTestMine;
   e_hit_test_region_r1->rect.SetRect(100, 100, 200, 400);
 
   auto e_hit_test_region_r2 = mojom::HitTestRegion::New();
-  e_hit_test_region_r2->surface_id = e_surface_id;
+  e_hit_test_region_r2->frame_sink_id = e_surface_id.frame_sink_id();
+  e_hit_test_region_r2->local_surface_id = e_surface_id.local_surface_id();
   e_hit_test_region_r2->flags = mojom::kHitTestMine;
   e_hit_test_region_r2->rect.SetRect(400, 100, 300, 400);
 
@@ -432,12 +436,14 @@
 
   auto e_hit_test_region_c1 = mojom::HitTestRegion::New();
   e_hit_test_region_c1->flags = mojom::kHitTestChildSurface;
-  e_hit_test_region_c1->surface_id = c1_surface_id;
+  e_hit_test_region_c1->frame_sink_id = c1_surface_id.frame_sink_id();
+  e_hit_test_region_c1->local_surface_id = c1_surface_id.local_surface_id();
   e_hit_test_region_c1->rect.SetRect(100, 100, 200, 300);
 
   auto e_hit_test_region_c2 = mojom::HitTestRegion::New();
   e_hit_test_region_c2->flags = mojom::kHitTestChildSurface;
-  e_hit_test_region_c2->surface_id = c2_surface_id;
+  e_hit_test_region_c2->frame_sink_id = c2_surface_id.frame_sink_id();
+  e_hit_test_region_c2->local_surface_id = c2_surface_id.local_surface_id();
   e_hit_test_region_c2->rect.SetRect(400, 100, 400, 300);
 
   e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_c1));
@@ -536,12 +542,14 @@
 
   auto e_hit_test_region_div = mojom::HitTestRegion::New();
   e_hit_test_region_div->flags = mojom::kHitTestMine;
-  e_hit_test_region_div->surface_id = e_surface_id;
+  e_hit_test_region_div->frame_sink_id = e_surface_id.frame_sink_id();
+  e_hit_test_region_div->local_surface_id = e_surface_id.local_surface_id();
   e_hit_test_region_div->rect.SetRect(200, 200, 300, 200);
 
   auto e_hit_test_region_c = mojom::HitTestRegion::New();
   e_hit_test_region_c->flags = mojom::kHitTestChildSurface;
-  e_hit_test_region_c->surface_id = c_surface_id;
+  e_hit_test_region_c->frame_sink_id = c_surface_id.frame_sink_id();
+  e_hit_test_region_c->local_surface_id = c_surface_id.local_surface_id();
   e_hit_test_region_c->rect.SetRect(100, 100, 200, 500);
 
   e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_div));
@@ -634,12 +642,14 @@
 
   auto e_hit_test_region_div = mojom::HitTestRegion::New();
   e_hit_test_region_div->flags = mojom::kHitTestMine;
-  e_hit_test_region_div->surface_id = e_surface_id;
+  e_hit_test_region_div->frame_sink_id = e_surface_id.frame_sink_id();
+  e_hit_test_region_div->local_surface_id = e_surface_id.local_surface_id();
   e_hit_test_region_div->rect.SetRect(200, 200, 300, 200);
 
   auto e_hit_test_region_c = mojom::HitTestRegion::New();
   e_hit_test_region_c->flags = mojom::kHitTestChildSurface;
-  e_hit_test_region_c->surface_id = c_surface_id;
+  e_hit_test_region_c->frame_sink_id = c_surface_id.frame_sink_id();
+  e_hit_test_region_c->local_surface_id = c_surface_id.local_surface_id();
   e_hit_test_region_c->rect.SetRect(100, 100, 200, 500);
 
   e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_c));
@@ -734,7 +744,8 @@
 
   auto e_hit_test_region_c = mojom::HitTestRegion::New();
   e_hit_test_region_c->flags = mojom::kHitTestChildSurface;
-  e_hit_test_region_c->surface_id = c_surface_id;
+  e_hit_test_region_c->frame_sink_id = c_surface_id.frame_sink_id();
+  e_hit_test_region_c->local_surface_id = c_surface_id.local_surface_id();
   e_hit_test_region_c->rect.SetRect(300, 100, 1600, 800);
   e_hit_test_region_c->transform.Translate(200, 100);
 
@@ -746,12 +757,14 @@
 
   auto c_hit_test_region_a = mojom::HitTestRegion::New();
   c_hit_test_region_a->flags = mojom::kHitTestChildSurface;
-  c_hit_test_region_a->surface_id = a_surface_id;
+  c_hit_test_region_a->frame_sink_id = a_surface_id.frame_sink_id();
+  c_hit_test_region_a->local_surface_id = a_surface_id.local_surface_id();
   c_hit_test_region_a->rect.SetRect(0, 0, 200, 100);
 
   auto c_hit_test_region_b = mojom::HitTestRegion::New();
   c_hit_test_region_b->flags = mojom::kHitTestChildSurface;
-  c_hit_test_region_b->surface_id = b_surface_id;
+  c_hit_test_region_b->frame_sink_id = b_surface_id.frame_sink_id();
+  c_hit_test_region_b->local_surface_id = b_surface_id.local_surface_id();
   c_hit_test_region_b->rect.SetRect(0, 100, 800, 600);
 
   c_hit_test_region_list->regions.push_back(std::move(c_hit_test_region_a));
@@ -876,7 +889,8 @@
 
   auto e_hit_test_region_c1 = mojom::HitTestRegion::New();
   e_hit_test_region_c1->flags = mojom::kHitTestChildSurface;
-  e_hit_test_region_c1->surface_id = c1_surface_id;
+  e_hit_test_region_c1->frame_sink_id = c1_surface_id.frame_sink_id();
+  e_hit_test_region_c1->local_surface_id = c1_surface_id.local_surface_id();
   e_hit_test_region_c1->rect.SetRect(100, 100, 700, 700);
 
   e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_c1));
@@ -887,7 +901,8 @@
 
   auto c1_hit_test_region_c2 = mojom::HitTestRegion::New();
   c1_hit_test_region_c2->flags = mojom::kHitTestChildSurface;
-  c1_hit_test_region_c2->surface_id = c2_surface_id;
+  c1_hit_test_region_c2->frame_sink_id = c2_surface_id.frame_sink_id();
+  c1_hit_test_region_c2->local_surface_id = c2_surface_id.local_surface_id();
   c1_hit_test_region_c2->rect.SetRect(100, 100, 500, 500);
 
   c1_hit_test_region_list->regions.push_back(std::move(c1_hit_test_region_c2));
@@ -898,7 +913,8 @@
 
   auto c2_hit_test_region_c3 = mojom::HitTestRegion::New();
   c2_hit_test_region_c3->flags = mojom::kHitTestChildSurface;
-  c2_hit_test_region_c3->surface_id = c3_surface_id;
+  c2_hit_test_region_c3->frame_sink_id = c3_surface_id.frame_sink_id();
+  c2_hit_test_region_c3->local_surface_id = c3_surface_id.local_surface_id();
   c2_hit_test_region_c3->rect.SetRect(100, 100, 300, 300);
 
   c2_hit_test_region_list->regions.push_back(std::move(c2_hit_test_region_c3));
@@ -1009,12 +1025,14 @@
 
   auto e_hit_test_region_div = mojom::HitTestRegion::New();
   e_hit_test_region_div->flags = mojom::kHitTestMine;
-  e_hit_test_region_div->surface_id = e_surface_id;
+  e_hit_test_region_div->frame_sink_id = e_surface_id.frame_sink_id();
+  e_hit_test_region_div->local_surface_id = e_surface_id.local_surface_id();
   e_hit_test_region_div->rect.SetRect(200, 200, 300, 200);
 
   auto e_hit_test_region_c = mojom::HitTestRegion::New();
   e_hit_test_region_c->flags = mojom::kHitTestChildSurface;
-  e_hit_test_region_c->surface_id = c_surface_id;
+  e_hit_test_region_c->frame_sink_id = c_surface_id.frame_sink_id();
+  e_hit_test_region_c->local_surface_id = c_surface_id.local_surface_id();
   e_hit_test_region_c->rect.SetRect(100, 100, 200, 500);
 
   e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_c));
@@ -1156,12 +1174,14 @@
 
   auto e_hit_test_region_div = mojom::HitTestRegion::New();
   e_hit_test_region_div->flags = mojom::kHitTestMine;
-  e_hit_test_region_div->surface_id = e_surface_id;
+  e_hit_test_region_div->frame_sink_id = e_surface_id.frame_sink_id();
+  e_hit_test_region_div->local_surface_id = e_surface_id.local_surface_id();
   e_hit_test_region_div->rect.SetRect(200, 200, 300, 200);
 
   auto e_hit_test_region_c = mojom::HitTestRegion::New();
   e_hit_test_region_c->flags = mojom::kHitTestChildSurface;
-  e_hit_test_region_c->surface_id = c_surface_id;
+  e_hit_test_region_c->frame_sink_id = c_surface_id.frame_sink_id();
+  e_hit_test_region_c->local_surface_id = c_surface_id.local_surface_id();
   e_hit_test_region_c->rect.SetRect(100, 100, 200, 500);
 
   e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_c));
diff --git a/components/wallpaper/wallpaper_manager_base.cc b/components/wallpaper/wallpaper_manager_base.cc
index 222bffd7..f55d28a5 100644
--- a/components/wallpaper/wallpaper_manager_base.cc
+++ b/components/wallpaper/wallpaper_manager_base.cc
@@ -565,8 +565,6 @@
     // Falls back to custom wallpaper that uses AccountId as part of its file
     // path.
     // Note that account id is used instead of wallpaper_files_id here.
-    LOG(ERROR) << "Failed to load custom wallpaper from its original fallback "
-                  "file path: " << valid_path.value();
     const std::string& old_path = account_id.GetUserEmail();  // Migrated
     valid_path = GetCustomWallpaperPath(kOriginalWallpaperSubDir,
                                         WallpaperFilesId::FromString(old_path),
@@ -574,13 +572,22 @@
   }
 
   if (!base::PathExists(valid_path)) {
+    user_manager::UserManager* user_manager = user_manager::UserManager::Get();
+    const user_manager::User* user = user_manager->FindUser(account_id);
     LOG(ERROR) << "Failed to load previously selected custom wallpaper. "
                << "Fallback to default wallpaper. Expected wallpaper path: "
-               << wallpaper_path.value();
+               << wallpaper_path.value() << ". Number of users on the device: "
+               << user_manager->GetUsers().size()
+               << ", Number of logged in users on the device: "
+               << user_manager->GetLoggedInUsers().size()
+               << ". Current user type: " << user->GetType()
+               << ", IsActiveUser=" << (user_manager->GetActiveUser() == user)
+               << ", IsPrimaryUser=" << (user_manager->GetPrimaryUser() == user)
+               << ".";
     reply_task_runner->PostTask(
-        FROM_HERE,
-        base::Bind(&WallpaperManagerBase::DoSetDefaultWallpaper, weak_ptr,
-                   account_id, base::Passed(std::move(on_finish))));
+        FROM_HERE, base::Bind(&WallpaperManagerBase::DoSetDefaultWallpaper,
+                              weak_ptr, account_id, update_wallpaper,
+                              base::Passed(std::move(on_finish))));
   } else {
     reply_task_runner->PostTask(
         FROM_HERE, base::Bind(&WallpaperManagerBase::StartLoad, weak_ptr,
@@ -831,7 +838,7 @@
     // In unexpected cases, revert to default wallpaper to fail safely. See
     // crosbug.com/38429.
     LOG(ERROR) << "Wallpaper reverts to default unexpected.";
-    DoSetDefaultWallpaper(account_id, std::move(on_finish));
+    DoSetDefaultWallpaper(account_id, update_wallpaper, std::move(on_finish));
   }
 }
 
diff --git a/components/wallpaper/wallpaper_manager_base.h b/components/wallpaper/wallpaper_manager_base.h
index ab761cce..8a895e95 100644
--- a/components/wallpaper/wallpaper_manager_base.h
+++ b/components/wallpaper/wallpaper_manager_base.h
@@ -481,9 +481,11 @@
   virtual void ScheduleSetUserWallpaper(const AccountId& account_id,
                                         bool delayed) = 0;
 
-  // Sets wallpaper to default.
+  // Sets wallpaper to default if |update_wallpaper| is true. Otherwise just
+  // load defaut wallpaper to cache.
   virtual void DoSetDefaultWallpaper(
       const AccountId& account_id,
+      bool update_wallpaper,
       MovableOnDestroyCallbackHolder on_finish) = 0;
 
   // Starts to load wallpaper at |wallpaper_path|. If |wallpaper_path| is
@@ -533,18 +535,21 @@
   virtual void SetDefaultWallpaperPathsFromCommandLine(
       base::CommandLine* command_line) = 0;
 
-  // Sets wallpaper to decoded default.
+  // Sets wallpaper to decoded default if |update_wallpaper| is true.
   virtual void OnDefaultWallpaperDecoded(
       const base::FilePath& path,
       const WallpaperLayout layout,
+      bool update_wallpaper,
       std::unique_ptr<user_manager::UserImage>* result,
       MovableOnDestroyCallbackHolder on_finish,
       std::unique_ptr<user_manager::UserImage> user_image) = 0;
 
-  // Start decoding given default wallpaper.
+  // Start decoding given default wallpaper and set it as wallpaper if
+  // |update_wallpaper| is true.
   virtual void StartLoadAndSetDefaultWallpaper(
       const base::FilePath& path,
       const WallpaperLayout layout,
+      bool update_wallpaper,
       MovableOnDestroyCallbackHolder on_finish,
       std::unique_ptr<user_manager::UserImage>* result_out) = 0;
 
diff --git a/content/browser/accessibility/browser_accessibility_com_win.cc b/content/browser/accessibility/browser_accessibility_com_win.cc
index eef62dcf..3a7d8db33 100644
--- a/content/browser/accessibility/browser_accessibility_com_win.cc
+++ b/content/browser/accessibility/browser_accessibility_com_win.cc
@@ -167,42 +167,6 @@
   return S_OK;
 }
 
-STDMETHODIMP BrowserAccessibilityComWin::get_groupPosition(
-    LONG* group_level,
-    LONG* similar_items_in_group,
-    LONG* position_in_group) {
-  WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_GROUP_POSITION);
-  AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes);
-  if (!owner())
-    return E_FAIL;
-
-  if (!group_level || !similar_items_in_group || !position_in_group)
-    return E_INVALIDARG;
-
-  *group_level = owner()->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL);
-  *similar_items_in_group = owner()->GetIntAttribute(ui::AX_ATTR_SET_SIZE);
-  *position_in_group = owner()->GetIntAttribute(ui::AX_ATTR_POS_IN_SET);
-
-  if (*group_level == *similar_items_in_group == *position_in_group == 0)
-    return S_FALSE;
-  return S_OK;
-}
-
-STDMETHODIMP
-BrowserAccessibilityComWin::get_localizedExtendedRole(
-    BSTR* localized_extended_role) {
-  WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_LOCALIZED_EXTENDED_ROLE);
-  AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes);
-  if (!owner())
-    return E_FAIL;
-
-  if (!localized_extended_role)
-    return E_INVALIDARG;
-
-  return GetStringAttributeAsBstr(ui::AX_ATTR_ROLE_DESCRIPTION,
-                                  localized_extended_role);
-}
-
 //
 // IAccessibleApplication methods.
 //
diff --git a/content/browser/accessibility/browser_accessibility_com_win.h b/content/browser/accessibility/browser_accessibility_com_win.h
index 80ad5b9..585da1d9 100644
--- a/content/browser/accessibility/browser_accessibility_com_win.h
+++ b/content/browser/accessibility/browser_accessibility_com_win.h
@@ -107,14 +107,6 @@
                 LONG x,
                 LONG y) override;
 
-  CONTENT_EXPORT STDMETHODIMP
-  get_groupPosition(LONG* group_level,
-                    LONG* similar_items_in_group,
-                    LONG* position_in_group) override;
-
-  CONTENT_EXPORT STDMETHODIMP
-  get_localizedExtendedRole(BSTR* localized_extended_role) override;
-
   //
   // IAccessibleApplication methods.
   //
diff --git a/content/browser/android/popup_zoomer.cc b/content/browser/android/popup_zoomer.cc
index 5c7a95b..8738e7c 100644
--- a/content/browser/android/popup_zoomer.cc
+++ b/content/browser/android/popup_zoomer.cc
@@ -40,10 +40,6 @@
   return reinterpret_cast<intptr_t>(popup_zoomer);
 }
 
-bool RegisterPopupZoomer(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 PopupZoomer::PopupZoomer(JNIEnv* env,
                          const JavaParamRef<jobject>& obj,
                          WebContents* web_contents)
diff --git a/content/browser/android/popup_zoomer.h b/content/browser/android/popup_zoomer.h
index eeed3e0..e3f33d5 100644
--- a/content/browser/android/popup_zoomer.h
+++ b/content/browser/android/popup_zoomer.h
@@ -52,8 +52,6 @@
   JavaObjectWeakGlobalRef java_obj_;
 };
 
-bool RegisterPopupZoomer(JNIEnv* env);
-
 }  // namespace content
 
 #endif  // CONTENT_BROWSER_ANDROID_POPUP_ZOOMER_H_
diff --git a/content/browser/download/download_browsertest.cc b/content/browser/download/download_browsertest.cc
index 77390a3..6fe9a11 100644
--- a/content/browser/download/download_browsertest.cc
+++ b/content/browser/download/download_browsertest.cc
@@ -2723,6 +2723,7 @@
                download->GetTargetFilePath().BaseName().value().c_str());
 }
 
+// Verify parallel download in normal case.
 IN_PROC_BROWSER_TEST_F(ParallelDownloadTest, ParallelDownloadComplete) {
   EXPECT_TRUE(base::FeatureList::IsEnabled(features::kParallelDownloading));
 
@@ -2749,6 +2750,76 @@
                             download->GetTargetFilePath());
 }
 
+// Verify parallel download resumption.
+IN_PROC_BROWSER_TEST_F(ParallelDownloadTest, ParallelDownloadResumption) {
+  EXPECT_TRUE(base::FeatureList::IsEnabled(features::kParallelDownloading));
+
+  TestDownloadRequestHandler request_handler;
+  TestDownloadRequestHandler::Parameters parameters;
+  parameters.etag = "ABC";
+  parameters.size = 3000000;
+  parameters.last_modified = std::string();
+  parameters.connection_type = net::HttpResponseInfo::CONNECTION_INFO_HTTP1_1;
+  request_handler.StartServing(parameters);
+
+  base::FilePath intermediate_file_path =
+      GetDownloadDirectory().AppendASCII("intermediate");
+  std::vector<GURL> url_chain;
+  url_chain.push_back(request_handler.url());
+
+  // Create an intermediate file that contains 3 chunks of data.
+  const int kIntermediateSize = 1000;
+  std::vector<char> buffer(kIntermediateSize);
+  request_handler.GetPatternBytes(parameters.pattern_generator_seed, 0,
+                                  buffer.size(), buffer.data());
+  {
+    base::ThreadRestrictions::ScopedAllowIO allow_io_for_test_setup;
+    base::File file(intermediate_file_path,
+                    base::File::FLAG_CREATE | base::File::FLAG_WRITE);
+    ASSERT_TRUE(file.IsValid());
+    request_handler.GetPatternBytes(parameters.pattern_generator_seed, 0,
+                                    buffer.size(), buffer.data());
+    EXPECT_EQ(kIntermediateSize,
+              file.Write(0, buffer.data(), kIntermediateSize));
+    request_handler.GetPatternBytes(parameters.pattern_generator_seed, 1000000,
+                                    buffer.size(), buffer.data());
+    EXPECT_EQ(kIntermediateSize,
+              file.Write(1000000, buffer.data(), kIntermediateSize));
+    request_handler.GetPatternBytes(parameters.pattern_generator_seed, 2000000,
+                                    buffer.size(), buffer.data());
+    EXPECT_EQ(kIntermediateSize,
+              file.Write(2000000, buffer.data(), kIntermediateSize));
+    file.Close();
+  }
+
+  // Create the received slices data that reflects the data in the file.
+  std::vector<DownloadItem::ReceivedSlice> received_slices = {
+      DownloadItem::ReceivedSlice(0, 1000),
+      DownloadItem::ReceivedSlice(1000000, 1000),
+      DownloadItem::ReceivedSlice(2000000, 1000)};
+
+  DownloadItem* download = DownloadManagerForShell(shell())->CreateDownloadItem(
+      "F7FB1F59-7DE1-4845-AFDB-8A688F70F583", 1, intermediate_file_path,
+      base::FilePath(), url_chain, GURL(), GURL(), GURL(), GURL(),
+      "application/octet-stream", "application/octet-stream", base::Time::Now(),
+      base::Time(), parameters.etag, parameters.last_modified,
+      kIntermediateSize * 3, parameters.size, std::string(),
+      DownloadItem::INTERRUPTED, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
+      DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED, false, base::Time(), false,
+      received_slices);
+
+  // Resume the parallel download with sparse file and received slices data.
+  download->Resume();
+  WaitForCompletion(download);
+
+  TestDownloadRequestHandler::CompletedRequests completed_requests;
+  request_handler.GetCompletedRequestInfo(&completed_requests);
+  EXPECT_EQ(kTestRequestCount, static_cast<int>(completed_requests.size()));
+
+  ReadAndVerifyFileContents(parameters.pattern_generator_seed, parameters.size,
+                            download->GetTargetFilePath());
+}
+
 // Test to verify that the browser-side enforcement of X-Frame-Options does
 // not impact downloads. Since XFO is only checked for subframes, this test
 // initiates a download in an iframe and expects it to succeed.
diff --git a/content/browser/download/download_create_info.h b/content/browser/download/download_create_info.h
index dbb5997..d2c85027 100644
--- a/content/browser/download/download_create_info.h
+++ b/content/browser/download/download_create_info.h
@@ -133,7 +133,9 @@
   // For continuing a download, the ETag of the file.
   std::string etag;
 
-  // If "Accept-Ranges:bytes" header presents in the response header.
+  // If the download response can be partial content.
+  // Either "Accept-Ranges" or "Content-Range" header presents in the
+  // response header.
   bool accept_range;
 
   // The HTTP connection type.
diff --git a/content/browser/download/download_item_impl.cc b/content/browser/download/download_item_impl.cc
index abe382f..ce19b3a6 100644
--- a/content/browser/download/download_item_impl.cc
+++ b/content/browser/download/download_item_impl.cc
@@ -60,6 +60,7 @@
 #include "content/public/common/content_features.h"
 #include "content/public/common/referrer.h"
 #include "net/http/http_response_headers.h"
+#include "net/http/http_status_code.h"
 #include "net/log/net_log.h"
 #include "net/log/net_log_event_type.h"
 #include "net/log/net_log_parameters_callback.h"
@@ -1388,9 +1389,9 @@
   if (state_ == RESUMING_INTERNAL)
     UpdateValidatorsOnResumption(new_create_info);
 
-  // If the download uses parallel requests, and choose not to create parallel
-  // request during resumption, clear the received_slices_ vector.
-  if (!IsParallelDownloadEnabled() && !received_slices_.empty()) {
+  // If the download is not parallel download during resumption, clear the
+  // |received_slices_|.
+  if (!job_->IsParallelizable() && !received_slices_.empty()) {
     destination_info_.received_bytes =
         GetMaxContiguousDataBlockSizeFromBeginning(received_slices_);
     received_slices_.clear();
@@ -1699,6 +1700,17 @@
   if (job_ && job_->IsParallelizable()) {
     RecordParallelizableDownloadCount(COMPLETED_COUNT,
                                       IsParallelDownloadEnabled());
+    int64_t content_length = -1;
+    if (response_headers_->response_code() != net::HTTP_PARTIAL_CONTENT) {
+      content_length = response_headers_->GetContentLength();
+    } else {
+      int64_t first_byte = -1;
+      int64_t last_byte = -1;
+      response_headers_->GetContentRangeFor206(&first_byte, &last_byte,
+                                               &content_length);
+    }
+    if (content_length > 0)
+      RecordParallelizableContentLength(content_length);
   }
 
   if (auto_opened_) {
diff --git a/content/browser/download/download_job_factory.cc b/content/browser/download/download_job_factory.cc
index a530ccf..79a9376 100644
--- a/content/browser/download/download_job_factory.cc
+++ b/content/browser/download/download_job_factory.cc
@@ -21,13 +21,15 @@
 namespace {
 
 // Returns if the download can be parallelized.
-bool IsParallelizableDownload(const DownloadCreateInfo& create_info) {
+bool IsParallelizableDownload(const DownloadCreateInfo& create_info,
+                              DownloadItemImpl* download_item) {
   // To enable parallel download, following conditions need to be satisfied.
   // 1. Feature |kParallelDownloading| enabled.
   // 2. Strong validators response headers. i.e. ETag and Last-Modified.
-  // 3. Accept-Ranges header.
+  // 3. Accept-Ranges or Content-Range header.
   // 4. Content-Length header.
-  // 5. Content-Length is no less than the minimum slice size configuration.
+  // 5. Content-Length is no less than the minimum slice size configuration, or
+  // persisted slices alreay exist.
   // 6. HTTP/1.1 protocol, not QUIC nor HTTP/1.0.
   // 7. HTTP or HTTPS scheme with GET method in the initial request.
 
@@ -38,6 +40,7 @@
       !create_info.etag.empty() || !create_info.last_modified.empty();
   bool has_content_length = create_info.total_bytes > 0;
   bool satisfy_min_file_size =
+      !download_item->GetReceivedSlices().empty() ||
       create_info.total_bytes >= GetMinSliceSizeConfig();
   bool satisfy_connection_type = create_info.connection_info ==
                                  net::HttpResponseInfo::CONNECTION_INFO_HTTP1_1;
@@ -97,7 +100,7 @@
                                                     std::move(req_handle));
   }
 
-  bool is_parallelizable = IsParallelizableDownload(create_info);
+  bool is_parallelizable = IsParallelizableDownload(create_info, download_item);
   // Build parallel download job.
   if (IsParallelDownloadEnabled() && is_parallelizable) {
     return base::MakeUnique<ParallelDownloadJob>(download_item,
diff --git a/content/browser/download/download_request_core.cc b/content/browser/download/download_request_core.cc
index 2f3619b..8eb85dc 100644
--- a/content/browser/download/download_request_core.cc
+++ b/content/browser/download/download_request_core.cc
@@ -278,8 +278,14 @@
     if (!headers->GetMimeType(&create_info->original_mime_type))
       create_info->original_mime_type.clear();
 
+    // Content-Range is validated in HandleSuccessfulServerResponse.
+    // In RFC 7233, a single part 206 partial response must generate
+    // Content-Range. Accept-Range may be sent in 200 response to indicate the
+    // server can handle range request, but optional in 206 response.
     create_info->accept_range =
-        headers->HasHeaderValue("Accept-Ranges", "bytes");
+        headers->HasHeaderValue("Accept-Ranges", "bytes") ||
+        (headers->HasHeader("Content-Range") &&
+         headers->response_code() == net::HTTP_PARTIAL_CONTENT);
   }
 
   // GURL::GetOrigin() doesn't support getting the inner origin of a blob URL.
diff --git a/content/browser/download/download_stats.cc b/content/browser/download/download_stats.cc
index 88ba7d9..2e6952a 100644
--- a/content/browser/download/download_stats.cc
+++ b/content/browser/download/download_stats.cc
@@ -798,6 +798,11 @@
   UMA_HISTOGRAM_BOOLEAN("Download.ParallelDownloadAddStreamSuccess", success);
 }
 
+void RecordParallelizableContentLength(int64_t content_length) {
+  UMA_HISTOGRAM_CUSTOM_COUNTS("Download.ContentLength.Parallelizable",
+                              content_length / 1024, 1, kMaxFileSizeKb, 50);
+}
+
 void RecordParallelizableDownloadStats(
     size_t bytes_downloaded_with_parallel_streams,
     base::TimeDelta time_with_parallel_streams,
diff --git a/content/browser/download/download_stats.h b/content/browser/download/download_stats.h
index e5e65b2..7ad51f6 100644
--- a/content/browser/download/download_stats.h
+++ b/content/browser/download/download_stats.h
@@ -269,6 +269,9 @@
                          base::TimeDelta disk_write_time,
                          base::TimeDelta elapsed_time);
 
+// Records the size of the download from content-length header.
+void RecordParallelizableContentLength(int64_t content_length);
+
 // Increment one of the count for parallelizable download.
 void RecordParallelizableDownloadCount(DownloadCountTypes type,
                                        bool is_parallel_download_enabled);
diff --git a/content/browser/download/parallel_download_job.cc b/content/browser/download/parallel_download_job.cc
index c800f09..30e6258f 100644
--- a/content/browser/download/parallel_download_job.cc
+++ b/content/browser/download/parallel_download_job.cc
@@ -135,7 +135,7 @@
   DCHECK(!requests_sent_);
   DCHECK(!is_paused());
   if (is_canceled_ ||
-      download_item_->GetLastReason() != DOWNLOAD_INTERRUPT_REASON_NONE) {
+      download_item_->GetState() != DownloadItem::DownloadState::IN_PROGRESS) {
     return;
   }
 
@@ -151,7 +151,15 @@
 
   DCHECK(!slices_to_download.empty());
   int64_t first_slice_offset = slices_to_download[0].offset;
-  DCHECK_LE(initial_request_offset_, first_slice_offset);
+
+  // We may build parallel job without slices. The slices can be cleared or
+  // previous session only has one stream writing to disk. In these cases, fall
+  // back to non parallel download.
+  if (initial_request_offset_ > first_slice_offset) {
+    VLOG(kVerboseLevel)
+        << "Received slices data mismatch initial request offset.";
+    return;
+  }
 
   // Create more slices for a new download. The initial request may generate
   // a received slice.
diff --git a/content/browser/download/parallel_download_job_unittest.cc b/content/browser/download/parallel_download_job_unittest.cc
index bc1d07e4..96f8a6e8 100644
--- a/content/browser/download/parallel_download_job_unittest.cc
+++ b/content/browser/download/parallel_download_job_unittest.cc
@@ -418,9 +418,9 @@
   EXPECT_CALL(callback, Run(_)).Times(1);
   job_->MakeFileInitialized(callback.Get(), DOWNLOAD_INTERRUPT_REASON_NONE);
 
-  // Simulate and inject an error from IO thread after file initializd.
-  EXPECT_CALL(*download_item_.get(), GetLastReason())
-      .WillOnce(Return(DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED));
+  // Simulate and inject an error from IO thread after file initialized.
+  EXPECT_CALL(*download_item_.get(), GetState())
+      .WillRepeatedly(Return(DownloadItem::DownloadState::INTERRUPTED));
 
   // Because of the error, no parallel requests are built.
   task_environment_.RunUntilIdle();
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc
index d4d50528..a44a04f 100644
--- a/content/browser/frame_host/navigation_request.cc
+++ b/content/browser/frame_host/navigation_request.cc
@@ -1098,8 +1098,8 @@
       "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. ";
-  parent->AddMessageToConsole(CONSOLE_MESSAGE_LEVEL_INFO, console_message);
+      "details.";
+  parent->AddMessageToConsole(CONSOLE_MESSAGE_LEVEL_WARNING, console_message);
 
   if (!base::FeatureList::IsEnabled(features::kBlockCredentialedSubresources))
     return CredentialedSubresourceCheckResult::ALLOW_REQUEST;
diff --git a/content/browser/frame_host/render_frame_host_delegate.h b/content/browser/frame_host/render_frame_host_delegate.h
index 83b6ca0..1d14bf05 100644
--- a/content/browser/frame_host/render_frame_host_delegate.h
+++ b/content/browser/frame_host/render_frame_host_delegate.h
@@ -249,6 +249,9 @@
   // WebContents is not live.
   virtual RenderFrameHost* GetFocusedFrameIncludingInnerWebContents();
 
+  // Called by when |source_rfh| advances focus to a RenderFrameProxyHost.
+  virtual void OnAdvanceFocus(RenderFrameHostImpl* source_rfh) {}
+
   // Creates a WebUI object for a frame navigating to |url|. If no WebUI
   // applies, returns null.
   virtual std::unique_ptr<WebUIImpl> CreateWebUIForRenderFrameHost(
diff --git a/content/browser/frame_host/render_frame_proxy_host.cc b/content/browser/frame_host/render_frame_proxy_host.cc
index b743e28..3bba011 100644
--- a/content/browser/frame_host/render_frame_proxy_host.cc
+++ b/content/browser/frame_host/render_frame_proxy_host.cc
@@ -356,6 +356,8 @@
           : nullptr;
 
   target_rfh->AdvanceFocus(type, source_proxy);
+  frame_tree_node_->current_frame_host()->delegate()->OnAdvanceFocus(
+      source_rfh);
 }
 
 void RenderFrameProxyHost::OnFrameFocused() {
diff --git a/content/browser/frame_host/render_widget_host_view_guest.cc b/content/browser/frame_host/render_widget_host_view_guest.cc
index e17b42ae1..a1abce1 100644
--- a/content/browser/frame_host/render_widget_host_view_guest.cc
+++ b/content/browser/frame_host/render_widget_host_view_guest.cc
@@ -85,6 +85,11 @@
       guest_(guest ? guest->AsWeakPtr() : base::WeakPtr<BrowserPluginGuest>()),
       platform_view_(platform_view),
       should_forward_text_selection_(false) {
+  // In tests |guest_| and therefore |owner| can be null.
+  auto* owner = GetOwnerRenderWidgetHostView();
+  if (owner)
+    SetParentFrameSinkId(owner->GetFrameSinkId());
+
   gfx::NativeView view = GetNativeView();
   if (view)
     UpdateScreenInfo(view);
@@ -259,10 +264,9 @@
   return platform_view_->GetSelectedText();
 }
 
-void RenderWidgetHostViewGuest::SetNeedsBeginFrames(
-    bool needs_begin_frames) {
- if (platform_view_)
-   platform_view_->SetNeedsBeginFrames(needs_begin_frames);
+void RenderWidgetHostViewGuest::SetNeedsBeginFrames(bool needs_begin_frames) {
+  if (platform_view_)
+    platform_view_->SetNeedsBeginFrames(needs_begin_frames);
 }
 
 TouchSelectionControllerClientManager*
diff --git a/content/browser/host_zoom_map_impl.cc b/content/browser/host_zoom_map_impl.cc
index 97f15ddc..9c7d78f 100644
--- a/content/browser/host_zoom_map_impl.cc
+++ b/content/browser/host_zoom_map_impl.cc
@@ -17,8 +17,6 @@
 #include "content/common/view_messages.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_types.h"
 #include "content/public/browser/resource_context.h"
 #include "content/public/browser/site_instance.h"
 #include "content/public/browser/storage_partition.h"
@@ -117,9 +115,6 @@
 
 HostZoomMapImpl::HostZoomMapImpl()
     : default_zoom_level_(0.0) {
-  registrar_.Add(
-      this, NOTIFICATION_RENDER_VIEW_HOST_WILL_CLOSE_RENDER_VIEW,
-      NotificationService::AllSources());
 }
 
 void HostZoomMapImpl::CopyFrom(HostZoomMap* copy_interface) {
@@ -490,23 +485,6 @@
                                               net::GetHostOrSpecFromURL(url));
 }
 
-void HostZoomMapImpl::Observe(int type,
-                              const NotificationSource& source,
-                              const NotificationDetails& details) {
-  switch (type) {
-    case NOTIFICATION_RENDER_VIEW_HOST_WILL_CLOSE_RENDER_VIEW: {
-      int render_view_id = Source<RenderViewHost>(source)->GetRoutingID();
-      int render_process_id =
-          Source<RenderViewHost>(source)->GetProcess()->GetID();
-      ClearTemporaryZoomLevel(render_process_id, render_view_id);
-      ClearPageScaleFactorIsOneForView(render_process_id, render_view_id);
-      break;
-    }
-    default:
-      NOTREACHED() << "Unexpected preference observed.";
-  }
-}
-
 void HostZoomMapImpl::ClearTemporaryZoomLevel(int render_process_id,
                                               int render_view_id) {
   {
@@ -553,6 +531,12 @@
   SendZoomLevelChange(std::string(), host, error_page_zoom_level);
 }
 
+void HostZoomMapImpl::WillCloseRenderView(int render_process_id,
+                                          int render_view_id) {
+  ClearTemporaryZoomLevel(render_process_id, render_view_id);
+  ClearPageScaleFactorIsOneForView(render_process_id, render_view_id);
+}
+
 HostZoomMapImpl::~HostZoomMapImpl() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 }
diff --git a/content/browser/host_zoom_map_impl.h b/content/browser/host_zoom_map_impl.h
index ec701680..0ba3bc9 100644
--- a/content/browser/host_zoom_map_impl.h
+++ b/content/browser/host_zoom_map_impl.h
@@ -15,17 +15,14 @@
 #include "base/sequenced_task_runner_helpers.h"
 #include "base/synchronization/lock.h"
 #include "content/public/browser/host_zoom_map.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
 
 namespace content {
 
 class WebContentsImpl;
 
 // HostZoomMap needs to be deleted on the UI thread because it listens
-// to notifications on there (and holds a NotificationRegistrar).
-class CONTENT_EXPORT HostZoomMapImpl : public HostZoomMap,
-                                       public NotificationObserver {
+// to notifications on there.
+class CONTENT_EXPORT HostZoomMapImpl : public HostZoomMap {
  public:
   HostZoomMapImpl();
   ~HostZoomMapImpl() override;
@@ -96,13 +93,10 @@
                              int render_process_id,
                              int render_view_id) const;
 
-  // NotificationObserver implementation.
-  void Observe(int type,
-               const NotificationSource& source,
-               const NotificationDetails& details) override;
-
   void SendErrorPageZoomLevelRefresh();
 
+  void WillCloseRenderView(int render_process_id, int render_view_id);
+
  private:
   typedef std::map<std::string, double> HostZoomLevels;
   typedef std::map<std::string, HostZoomLevels> SchemeHostZoomLevels;
@@ -156,8 +150,6 @@
   // guarantee thread safety.
   mutable base::Lock lock_;
 
-  NotificationRegistrar registrar_;
-
   DISALLOW_COPY_AND_ASSIGN(HostZoomMapImpl);
 };
 
diff --git a/content/browser/permissions/permission_service_impl.cc b/content/browser/permissions/permission_service_impl.cc
index 8028cf6..ce9f265 100644
--- a/content/browser/permissions/permission_service_impl.cc
+++ b/content/browser/permissions/permission_service_impl.cc
@@ -56,6 +56,8 @@
       return PermissionType::BACKGROUND_SYNC;
     case PermissionName::SENSORS:
       return PermissionType::SENSORS;
+    case PermissionName::ACCESSIBILITY_EVENTS:
+      return PermissionType::ACCESSIBILITY_EVENTS;
   }
 
   NOTREACHED();
@@ -82,6 +84,7 @@
     case PermissionType::BACKGROUND_SYNC:
     case PermissionType::FLASH:
     case PermissionType::SENSORS:
+    case PermissionType::ACCESSIBILITY_EVENTS:
     case PermissionType::NUM:
       // These aren't exposed by feature policy.
       return blink::WebFeaturePolicyFeature::kNotFound;
diff --git a/content/browser/posix_file_descriptor_info_impl_unittest.cc b/content/browser/posix_file_descriptor_info_impl_unittest.cc
index 6f4903d..0500d03 100644
--- a/content/browser/posix_file_descriptor_info_impl_unittest.cc
+++ b/content/browser/posix_file_descriptor_info_impl_unittest.cc
@@ -22,7 +22,7 @@
 // Returns true if fd was already closed.  Closes fd if not closed.
 // TODO(morrita) Merge with things in file_descriptor_set_posix_unittest.cc
 bool VerifyClosed(int fd) {
-  const int duped = dup(fd);
+  const int duped = HANDLE_EINTR(dup(fd));
   if (duped != -1) {
     EXPECT_NE(IGNORE_EINTR(close(duped)), -1);
     EXPECT_NE(IGNORE_EINTR(close(fd)), -1);
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc
index 1596a43..d1399176 100644
--- a/content/browser/renderer_host/render_view_host_impl.cc
+++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -573,10 +573,10 @@
 
     // TODO(creis): Should this be moved to Shutdown?  It may not be called for
     // RenderViewHosts that have been swapped out.
-    NotificationService::current()->Notify(
-        NOTIFICATION_RENDER_VIEW_HOST_WILL_CLOSE_RENDER_VIEW,
-        Source<RenderViewHost>(this),
-        NotificationService::NoDetails());
+#if !defined(OS_ANDROID)
+    static_cast<HostZoomMapImpl*>(HostZoomMap::Get(GetSiteInstance()))
+        ->WillCloseRenderView(GetProcess()->GetID(), GetRoutingID());
+#endif
 
     Send(new ViewMsg_ClosePage(GetRoutingID()));
   } else {
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc
index 8ba7840..f4f522d 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.cc
+++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -963,7 +963,12 @@
 }
 
 bool RenderWidgetHostViewAndroid::OnTouchEvent(
-    const ui::MotionEvent& event) {
+    const ui::MotionEventAndroid& event) {
+  RecordToolTypeForActionDown(event);
+
+  if (event.for_touch_handle())
+    return OnTouchHandleEvent(event);
+
   if (!host_ || !host_->delegate())
     return false;
 
@@ -977,8 +982,7 @@
   // If a browser-based widget consumes the touch event, it's critical that
   // touch event interception be disabled. This avoids issues with
   // double-handling for embedder-detected gestures like side swipe.
-  if (touch_selection_controller_ &&
-      touch_selection_controller_->WillHandleTouchEvent(event)) {
+  if (OnTouchHandleEvent(event)) {
     RequestDisallowInterceptTouchEvent();
     return true;
   }
@@ -2154,15 +2158,6 @@
   return touch_selection_controller_client_manager_.get();
 }
 
-bool RenderWidgetHostViewAndroid::OnTouchEvent(
-    const ui::MotionEventAndroid& event,
-    bool for_touch_handle) {
-  RecordToolTypeForActionDown(event);
-
-  // TODO(jinsukkim): Remove this distinction.
-  return for_touch_handle ? OnTouchHandleEvent(event) : OnTouchEvent(event);
-}
-
 bool RenderWidgetHostViewAndroid::OnMouseEvent(
     const ui::MotionEventAndroid& event) {
   RecordToolTypeForActionDown(event);
diff --git a/content/browser/renderer_host/render_widget_host_view_android.h b/content/browser/renderer_host/render_widget_host_view_android.h
index 898bbe96..5b99f6d 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.h
+++ b/content/browser/renderer_host/render_widget_host_view_android.h
@@ -194,8 +194,7 @@
   GetTouchSelectionControllerClientManager() override;
 
   // ui::ViewClient implementation.
-  bool OnTouchEvent(const ui::MotionEventAndroid& m,
-                    bool for_touch_handle) override;
+  bool OnTouchEvent(const ui::MotionEventAndroid& m) override;
   bool OnMouseEvent(const ui::MotionEventAndroid& m) override;
   bool OnMouseWheelEvent(const ui::MotionEventAndroid& event) override;
   void OnPhysicalBackingSizeChanged() override;
@@ -276,7 +275,6 @@
 
   base::WeakPtr<RenderWidgetHostViewAndroid> GetWeakPtrAndroid();
 
-  bool OnTouchEvent(const ui::MotionEvent& event);
   bool OnTouchHandleEvent(const ui::MotionEvent& event);
   int GetTouchHandleHeight();
   void ResetGestureDetection();
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame.cc b/content/browser/renderer_host/render_widget_host_view_child_frame.cc
index 1c5fec5..108b5d9 100644
--- a/content/browser/renderer_host/render_widget_host_view_child_frame.cc
+++ b/content/browser/renderer_host/render_widget_host_view_child_frame.cc
@@ -121,11 +121,7 @@
     return;
 
   if (frame_connector_) {
-    if (parent_frame_sink_id_.is_valid() && !IsUsingMus()) {
-      GetHostFrameSinkManager()->UnregisterFrameSinkHierarchy(
-          parent_frame_sink_id_, frame_sink_id_);
-    }
-    parent_frame_sink_id_ = viz::FrameSinkId();
+    SetParentFrameSinkId(viz::FrameSinkId());
     last_received_local_surface_id_ = viz::LocalSurfaceId();
 
     // Unlocks the mouse if this RenderWidgetHostView holds the lock.
@@ -137,12 +133,8 @@
     RenderWidgetHostViewBase* parent_view =
         frame_connector_->GetParentRenderWidgetHostView();
     if (parent_view) {
-      parent_frame_sink_id_ = parent_view->GetFrameSinkId();
-      DCHECK(parent_frame_sink_id_.is_valid());
-      if (!IsUsingMus()) {
-        GetHostFrameSinkManager()->RegisterFrameSinkHierarchy(
-            parent_frame_sink_id_, frame_sink_id_);
-      }
+      DCHECK(parent_view->GetFrameSinkId().is_valid());
+      SetParentFrameSinkId(parent_view->GetFrameSinkId());
     }
 
     auto* root_view = frame_connector_->GetRootRenderWidgetHostView();
@@ -462,7 +454,8 @@
 
 void RenderWidgetHostViewChildFrame::DidReceiveCompositorFrameAck(
     const std::vector<viz::ReturnedResource>& resources) {
-  renderer_compositor_frame_sink_->DidReceiveCompositorFrameAck(resources);
+  if (renderer_compositor_frame_sink_)
+    renderer_compositor_frame_sink_->DidReceiveCompositorFrameAck(resources);
 }
 
 void RenderWidgetHostViewChildFrame::DidCreateNewRendererCompositorFrameSink(
@@ -473,6 +466,28 @@
   has_frame_ = false;
 }
 
+void RenderWidgetHostViewChildFrame::SetParentFrameSinkId(
+    const viz::FrameSinkId& parent_frame_sink_id) {
+  if (parent_frame_sink_id_ == parent_frame_sink_id || IsUsingMus())
+    return;
+
+  auto* host_frame_sink_manager = GetHostFrameSinkManager();
+
+  // Unregister hierarchy for the current parent, only if set.
+  if (parent_frame_sink_id_.is_valid()) {
+    host_frame_sink_manager->UnregisterFrameSinkHierarchy(parent_frame_sink_id_,
+                                                          frame_sink_id_);
+  }
+
+  parent_frame_sink_id_ = parent_frame_sink_id;
+
+  // Register hierarchy for the new parent, only if set.
+  if (parent_frame_sink_id_.is_valid()) {
+    host_frame_sink_manager->RegisterFrameSinkHierarchy(parent_frame_sink_id_,
+                                                        frame_sink_id_);
+  }
+}
+
 void RenderWidgetHostViewChildFrame::ProcessCompositorFrame(
     const viz::LocalSurfaceId& local_surface_id,
     cc::CompositorFrame frame) {
@@ -774,16 +789,19 @@
 
 void RenderWidgetHostViewChildFrame::ReclaimResources(
     const std::vector<viz::ReturnedResource>& resources) {
-  renderer_compositor_frame_sink_->ReclaimResources(resources);
+  if (renderer_compositor_frame_sink_)
+    renderer_compositor_frame_sink_->ReclaimResources(resources);
 }
 
 void RenderWidgetHostViewChildFrame::OnBeginFrame(
     const viz::BeginFrameArgs& args) {
-  renderer_compositor_frame_sink_->OnBeginFrame(args);
+  if (renderer_compositor_frame_sink_)
+    renderer_compositor_frame_sink_->OnBeginFrame(args);
 }
 
 void RenderWidgetHostViewChildFrame::OnBeginFramePausedChanged(bool paused) {
-  renderer_compositor_frame_sink_->OnBeginFramePausedChanged(paused);
+  if (renderer_compositor_frame_sink_)
+    renderer_compositor_frame_sink_->OnBeginFramePausedChanged(paused);
 }
 
 void RenderWidgetHostViewChildFrame::OnFirstSurfaceActivation(
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame.h b/content/browser/renderer_host/render_widget_host_view_child_frame.h
index 802ce0c..7a6cb8fb 100644
--- a/content/browser/renderer_host/render_widget_host_view_child_frame.h
+++ b/content/browser/renderer_host/render_widget_host_view_child_frame.h
@@ -226,6 +226,10 @@
   explicit RenderWidgetHostViewChildFrame(RenderWidgetHost* widget);
   void Init();
 
+  // Sets |parent_frame_sink_id_| and registers frame sink hierarchy. If the
+  // parent was already set then it also unregisters hierarchy.
+  void SetParentFrameSinkId(const viz::FrameSinkId& parent_frame_sink_id);
+
   void ProcessCompositorFrame(const viz::LocalSurfaceId& local_surface_id,
                               cc::CompositorFrame frame);
 
@@ -313,4 +317,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_FRAME_HOST_RENDER_WIDGET_HOST_VIEW_CHILD_FRAME_H_
+#endif  // CONTENT_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_VIEW_CHILD_FRAME_H_
diff --git a/content/browser/resources/media/stats_graph_helper.js b/content/browser/resources/media/stats_graph_helper.js
index 25346cd..daa2886 100644
--- a/content/browser/resources/media/stats_graph_helper.js
+++ b/content/browser/resources/media/stats_graph_helper.js
@@ -346,7 +346,7 @@
   for (var prop in bweCompoundGraphConfig) {
     var div = document.createElement('div');
     legend.appendChild(div);
-    div.innerHTML = '<input type=checkbox checked></input>' + prop;
+    div.innerHTML = '<input type=checkbox checked>' + prop;
     div.style.color = bweCompoundGraphConfig[prop].color;
     div.dataSeriesId = reportId + '-' + prop;
     div.graphViewId =
diff --git a/content/browser/service_worker/embedded_worker_instance.cc b/content/browser/service_worker/embedded_worker_instance.cc
index 686b15e9..c7dfe86 100644
--- a/content/browser/service_worker/embedded_worker_instance.cc
+++ b/content/browser/service_worker/embedded_worker_instance.cc
@@ -515,7 +515,7 @@
   inflight_start_task_->Start(std::move(params), callback);
 }
 
-bool EmbeddedWorkerInstance::Stop() {
+void EmbeddedWorkerInstance::Stop() {
   DCHECK(status_ == EmbeddedWorkerStatus::STARTING ||
          status_ == EmbeddedWorkerStatus::RUNNING)
       << static_cast<int>(status_);
@@ -523,21 +523,20 @@
   // Abort an inflight start task.
   inflight_start_task_.reset();
 
+  // Don't send the StopWorker message if the StartWorker message hasn't
+  // been sent.
   if (status_ == EmbeddedWorkerStatus::STARTING &&
       !HasSentStartWorker(starting_phase())) {
-    // Don't send the StopWorker message when the StartWorker message hasn't
-    // been sent.
-    // TODO(shimazu): Invoke OnStopping/OnStopped after the legacy IPC path is
-    // removed.
-    OnDetached();
-    return false;
+    ReleaseProcess();
+    for (auto& observer : listener_list_)
+      observer.OnStopped(EmbeddedWorkerStatus::STARTING /* old_status */);
+    return;
   }
-  client_->StopWorker();
 
+  client_->StopWorker();
   status_ = EmbeddedWorkerStatus::STOPPING;
   for (auto& observer : listener_list_)
     observer.OnStopping();
-  return true;
 }
 
 void EmbeddedWorkerInstance::StopIfIdle() {
@@ -817,20 +816,17 @@
     observer.OnStopped(old_status);
 }
 
-void EmbeddedWorkerInstance::OnDetached() {
-  EmbeddedWorkerStatus old_status = status_;
-  ReleaseProcess();
-  for (auto& observer : listener_list_)
-    observer.OnDetached(old_status);
-}
-
 void EmbeddedWorkerInstance::Detach() {
   // Temporary CHECK for debugging https://crbug.com/750267.
   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
   if (status() == EmbeddedWorkerStatus::STOPPED)
     return;
   registry_->DetachWorker(process_id(), embedded_worker_id());
-  OnDetached();
+
+  EmbeddedWorkerStatus old_status = status_;
+  ReleaseProcess();
+  for (auto& observer : listener_list_)
+    observer.OnDetached(old_status);
 }
 
 base::WeakPtr<EmbeddedWorkerInstance> EmbeddedWorkerInstance::AsWeakPtr() {
diff --git a/content/browser/service_worker/embedded_worker_instance.h b/content/browser/service_worker/embedded_worker_instance.h
index 32b800dd..4c063323 100644
--- a/content/browser/service_worker/embedded_worker_instance.h
+++ b/content/browser/service_worker/embedded_worker_instance.h
@@ -91,11 +91,22 @@
     virtual void OnThreadStarted() {}
     virtual void OnStarted() {}
 
+    // Called when status changed to STOPPING. The renderer has been sent a Stop
+    // IPC message and OnStopped() will be called upon successful completion.
     virtual void OnStopping() {}
-    // Received ACK from renderer that the worker context terminated.
+
+    // Called when status changed to STOPPED. Usually, this is called upon
+    // receiving an ACK from renderer that the worker context terminated.
+    // OnStopped() is also called if Stop() aborted an ongoing start attempt
+    // even before the Start IPC message was sent to the renderer.  In this
+    // case, OnStopping() is not called; the worker is "stopped" immediately
+    // (the Start IPC is never sent).
     virtual void OnStopped(EmbeddedWorkerStatus old_status) {}
-    // The browser-side IPC endpoint for communication with the worker died.
+
+    // Called when the browser-side IPC endpoint for communication with the
+    // worker died. When this is called, status is STOPPED.
     virtual void OnDetached(EmbeddedWorkerStatus old_status) {}
+
     virtual void OnScriptLoaded() {}
     virtual void OnScriptLoadFailed() {}
     virtual void OnReportException(const base::string16& error_message,
@@ -128,10 +139,15 @@
              mojom::ServiceWorkerInstalledScriptsInfoPtr installed_scripts_info,
              const StatusCallback& callback);
 
-  // Stops the worker. It is invalid to call this when the worker is
-  // not in STARTING or RUNNING status.
-  // This returns false when StopWorker IPC couldn't be sent to the worker.
-  bool Stop();
+  // Stops the worker. It is invalid to call this when the worker is not in
+  // STARTING or RUNNING status.
+  //
+  // Stop() typically sends a Stop IPC to the renderer, and this instance enters
+  // STOPPING status, with Listener::OnStopped() called upon completion. It can
+  // synchronously complete if this instance is STARTING but the Start IPC
+  // message has not yet been sent. In that case, the start procedure is
+  // aborted, and this instance enters STOPPED status.
+  void Stop();
 
   // Stops the worker if the worker is not being debugged (i.e. devtools is
   // not attached). This method is called by a stop-worker timer to kill
@@ -198,10 +214,11 @@
   static std::string StatusToString(EmbeddedWorkerStatus status);
   static std::string StartingPhaseToString(StartingPhase phase);
 
-  // Detaches the running worker from the EmbeddedWorkerRegistry and calls
-  // OnDetached(). Use this instead of OnDetached() when the
-  // EmbeddedWorkerRegistry possibly knows about the running worker.
-  // TODO(falken): Remove OnDetached() once the callsite in Stop() is removed.
+  // Forces this instance into STOPPED status and releases any state about the
+  // running worker. Called when connection with the renderer died or the
+  // renderer is unresponsive.  Essentially, it throws away any information
+  // about the renderer-side worker, and frees this instance up to start a new
+  // worker.
   void Detach();
 
   base::WeakPtr<EmbeddedWorkerInstance> AsWeakPtr();
@@ -263,10 +280,6 @@
                               int line_number,
                               const GURL& source_url) override;
 
-  // Called when connection with the renderer died or the start attempt was
-  // aborted before the connection was attempted.
-  void OnDetached();
-
   // Called back from Registry when the worker instance sends message
   // to the browser (i.e. EmbeddedWorker observers).
   // Returns false if the message is not handled.
diff --git a/content/browser/service_worker/embedded_worker_instance_unittest.cc b/content/browser/service_worker/embedded_worker_instance_unittest.cc
index ef25ce5..adcca12 100644
--- a/content/browser/service_worker/embedded_worker_instance_unittest.cc
+++ b/content/browser/service_worker/embedded_worker_instance_unittest.cc
@@ -44,7 +44,7 @@
 
 }  // namespace
 
-class ProviderHostEndpoints : public mojom::ServiceWorkerProviderHost {
+class ProviderHostEndpoints : public mojom::ServiceWorkerContainerHost {
  public:
   ProviderHostEndpoints() : binding_(this) {}
 
@@ -62,8 +62,8 @@
   }
 
  private:
-  mojom::ServiceWorkerProviderAssociatedPtr client_;
-  mojo::AssociatedBinding<mojom::ServiceWorkerProviderHost> binding_;
+  mojom::ServiceWorkerContainerAssociatedPtr client_;
+  mojo::AssociatedBinding<mojom::ServiceWorkerContainerHost> binding_;
 
   DISALLOW_COPY_AND_ASSIGN(ProviderHostEndpoints);
 };
@@ -290,7 +290,7 @@
   EXPECT_EQ(helper_->mock_render_process_id(), worker->process_id());
 
   // Stop the worker.
-  EXPECT_TRUE(worker->Stop());
+  worker->Stop();
   EXPECT_EQ(EmbeddedWorkerStatus::STOPPING, worker->status());
   base::RunLoop().RunUntilIdle();
 
@@ -344,7 +344,7 @@
     // The worker should be using the default render process.
     EXPECT_EQ(helper_->mock_render_process_id(), worker->process_id());
 
-    EXPECT_TRUE(worker->Stop());
+    worker->Stop();
     base::RunLoop().RunUntilIdle();
   }
 
@@ -371,7 +371,7 @@
     EXPECT_EQ(EmbeddedWorkerStatus::RUNNING, worker->status());
     // The worker should be using the new render process.
     EXPECT_EQ(helper_->new_render_process_id(), worker->process_id());
-    EXPECT_TRUE(worker->Stop());
+    worker->Stop();
     base::RunLoop().RunUntilIdle();
   }
 }
@@ -416,7 +416,7 @@
 
   // Calling Stop() actually stops the worker regardless of whether devtools
   // is attached or not.
-  EXPECT_TRUE(worker->Stop());
+  worker->Stop();
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(EmbeddedWorkerStatus::STOPPED, worker->status());
 }
@@ -586,7 +586,7 @@
 
   // "PROCESS_ALLOCATED" event should not be recorded.
   ASSERT_EQ(1u, events_.size());
-  EXPECT_EQ(DETACHED, events_[0].type);
+  EXPECT_EQ(STOPPED, events_[0].type);
   EXPECT_EQ(EmbeddedWorkerStatus::STARTING, events_[0].status);
   events_.clear();
 
diff --git a/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc b/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc
index d00f67a2..6bca0a6 100644
--- a/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc
+++ b/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc
@@ -53,14 +53,14 @@
 }
 
 struct RemoteProviderInfo {
-  mojom::ServiceWorkerProviderHostAssociatedPtr host_ptr;
-  mojom::ServiceWorkerProviderAssociatedRequest client_request;
+  mojom::ServiceWorkerContainerHostAssociatedPtr host_ptr;
+  mojom::ServiceWorkerContainerAssociatedRequest client_request;
 };
 
 RemoteProviderInfo SetupProviderHostInfoPtrs(
     ServiceWorkerProviderHostInfo* host_info) {
   RemoteProviderInfo remote_info;
-  mojom::ServiceWorkerProviderAssociatedPtr browser_side_client_ptr;
+  mojom::ServiceWorkerContainerAssociatedPtr browser_side_client_ptr;
   remote_info.client_request =
       mojo::MakeIsolatedRequest(&browser_side_client_ptr);
   host_info->host_request = mojo::MakeIsolatedRequest(&remote_info.host_ptr);
diff --git a/content/browser/service_worker/service_worker_provider_host.cc b/content/browser/service_worker/service_worker_provider_host.cc
index 81ace230..e05fd96 100644
--- a/content/browser/service_worker/service_worker_provider_host.cc
+++ b/content/browser/service_worker/service_worker_provider_host.cc
@@ -188,7 +188,7 @@
     return;
   }
 
-  provider_.Bind(std::move(info_.client_ptr_info));
+  container_.Bind(std::move(info_.client_ptr_info));
   binding_.Bind(std::move(info_.host_request));
   binding_.set_connection_error_handler(base::BindOnce(
       &RemoveProviderHost, context_, render_process_id, info_.provider_id));
@@ -552,7 +552,7 @@
       base::WrapUnique(new ServiceWorkerProviderHost(
           process_id(),
           ServiceWorkerProviderHostInfo(std::move(info_), binding_.Unbind(),
-                                        provider_.PassInterface()),
+                                        container_.PassInterface()),
           context_, dispatcher_host()));
 
   for (const GURL& pattern : associated_patterns_)
@@ -587,9 +587,9 @@
   info_ = std::move(provisional_host->info_);
 
   // Take the connection over from the provisional host.
-  DCHECK(!provider_.is_bound());
+  DCHECK(!container_.is_bound());
   DCHECK(!binding_.is_bound());
-  provider_.Bind(provisional_host->provider_.PassInterface());
+  container_.Bind(provisional_host->container_.PassInterface());
   binding_.Bind(provisional_host->binding_.Unbind());
   binding_.set_connection_error_handler(
       base::BindOnce(&RemoveProviderHost, context_,
@@ -621,10 +621,10 @@
   DCHECK_EQ(info_.provider_id, info.provider_id);
   DCHECK_NE(MSG_ROUTING_NONE, info.route_id);
 
-  // Connect with the provider on the renderer.
-  DCHECK(!provider_.is_bound());
+  // Connect with the mojom::ServiceWorkerContainer on the renderer.
+  DCHECK(!container_.is_bound());
   DCHECK(!binding_.is_bound());
-  provider_.Bind(std::move(info.client_ptr_info));
+  container_.Bind(std::move(info.client_ptr_info));
   binding_.Bind(std::move(info.host_request));
   binding_.set_connection_error_handler(
       base::BindOnce(&RemoveProviderHost, context_, process_id, provider_id()));
@@ -683,7 +683,7 @@
   provider_info->provider_id = provider_id();
   provider_info->attributes = std::move(attrs);
   provider_info->registration = std::move(info);
-  provider_info->client_request = mojo::MakeRequest(&provider_);
+  provider_info->client_request = mojo::MakeRequest(&container_);
 
   mojom::URLLoaderFactoryAssociatedPtrInfo script_loader_factory_ptr_info;
   if (ServiceWorkerUtils::IsServicificationEnabled()) {
diff --git a/content/browser/service_worker/service_worker_provider_host.h b/content/browser/service_worker/service_worker_provider_host.h
index 6c2a123..4be1822 100644
--- a/content/browser/service_worker/service_worker_provider_host.h
+++ b/content/browser/service_worker/service_worker_provider_host.h
@@ -21,9 +21,9 @@
 #include "base/time/time.h"
 #include "content/browser/service_worker/service_worker_registration.h"
 #include "content/common/content_export.h"
+#include "content/common/service_worker/service_worker_container.mojom.h"
 #include "content/common/service_worker/service_worker_event_dispatcher.mojom.h"
 #include "content/common/service_worker/service_worker_provider_host_info.h"
-#include "content/common/service_worker/service_worker_provider_interfaces.mojom.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "content/public/common/request_context_frame_type.h"
 #include "content/public/common/request_context_type.h"
@@ -79,7 +79,7 @@
 class CONTENT_EXPORT ServiceWorkerProviderHost
     : public ServiceWorkerRegistration::Listener,
       public base::SupportsWeakPtr<ServiceWorkerProviderHost>,
-      public mojom::ServiceWorkerProviderHost {
+      public mojom::ServiceWorkerContainerHost {
  public:
   using GetRegistrationForReadyCallback =
       base::Callback<void(ServiceWorkerRegistration* reigstration)>;
@@ -443,15 +443,16 @@
   ServiceWorkerDispatcherHost* dispatcher_host_;
   bool allow_association_;
 
-  // |provider_| is the renderer-side Mojo endpoint for provider.
-  mojom::ServiceWorkerProviderAssociatedPtr provider_;
+  // |container_| is the Mojo endpoint to the renderer-side
+  // ServiceWorkerContainer that |this| is a ServiceWorkerContainerHost for.
+  mojom::ServiceWorkerContainerAssociatedPtr container_;
   // |binding_| is the Mojo binding that keeps the connection to the
   // renderer-side counterpart (content::ServiceWorkerNetworkProvider). When the
   // connection bound on |binding_| gets killed from the renderer side, or the
   // bound |ServiceWorkerProviderInfoForStartWorker::host_ptr_info| is otherwise
   // destroyed before being passed to the renderer, this
   // content::ServiceWorkerProviderHost will be destroyed.
-  mojo::AssociatedBinding<mojom::ServiceWorkerProviderHost> binding_;
+  mojo::AssociatedBinding<mojom::ServiceWorkerContainerHost> binding_;
 
   std::vector<base::Closure> queued_events_;
 
diff --git a/content/browser/service_worker/service_worker_test_utils.cc b/content/browser/service_worker/service_worker_test_utils.cc
index 7d99416..11ec5dd 100644
--- a/content/browser/service_worker/service_worker_test_utils.cc
+++ b/content/browser/service_worker/service_worker_test_utils.cc
@@ -22,7 +22,7 @@
 
 void ServiceWorkerRemoteProviderEndpoint::BindWithProviderHostInfo(
     content::ServiceWorkerProviderHostInfo* info) {
-  mojom::ServiceWorkerProviderAssociatedPtr client_ptr;
+  mojom::ServiceWorkerContainerAssociatedPtr client_ptr;
   client_request_ = mojo::MakeIsolatedRequest(&client_ptr);
   info->client_ptr_info = client_ptr.PassInterface();
   info->host_request = mojo::MakeIsolatedRequest(&host_ptr_);
diff --git a/content/browser/service_worker/service_worker_test_utils.h b/content/browser/service_worker/service_worker_test_utils.h
index dc7217c4..1f01c94 100644
--- a/content/browser/service_worker/service_worker_test_utils.h
+++ b/content/browser/service_worker/service_worker_test_utils.h
@@ -62,21 +62,21 @@
   void BindWithProviderInfo(
       mojom::ServiceWorkerProviderInfoForStartWorkerPtr info);
 
-  mojom::ServiceWorkerProviderHostAssociatedPtr* host_ptr() {
+  mojom::ServiceWorkerContainerHostAssociatedPtr* host_ptr() {
     return &host_ptr_;
   }
 
-  mojom::ServiceWorkerProviderAssociatedRequest* client_request() {
+  mojom::ServiceWorkerContainerAssociatedRequest* client_request() {
     return &client_request_;
   }
 
  private:
   // Bound with content::ServiceWorkerProviderHost. The provider host will be
   // removed asynchronously when this pointer is closed.
-  mojom::ServiceWorkerProviderHostAssociatedPtr host_ptr_;
-  // This is the other end of ServiceWorkerProviderAssociatedPtr owned by
+  mojom::ServiceWorkerContainerHostAssociatedPtr host_ptr_;
+  // This is the other end of ServiceWorkerContainerAssociatedPtr owned by
   // content::ServiceWorkerProviderHost.
-  mojom::ServiceWorkerProviderAssociatedRequest client_request_;
+  mojom::ServiceWorkerContainerAssociatedRequest client_request_;
 
   DISALLOW_COPY_AND_ASSIGN(ServiceWorkerRemoteProviderEndpoint);
 };
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc
index 074adbe0..bb9f250 100644
--- a/content/browser/service_worker/service_worker_version.cc
+++ b/content/browser/service_worker/service_worker_version.cc
@@ -480,13 +480,9 @@
   switch (running_status()) {
     case EmbeddedWorkerStatus::STARTING:
     case EmbeddedWorkerStatus::RUNNING:
-      // Stop() returns false when it's called before StartWorker message hasn't
-      // been sent to the renderer process even though EmbeddedWorkerInstance is
-      // stopped properly.
-      // TODO(shimazu): Remove this check after Stop() hides the IPC behavior.
-      // See also a TODO on EmbeddedWorkerInstance::Stop.
-      if (!embedded_worker_->Stop()) {
-        RunSoon(base::BindOnce(callback, SERVICE_WORKER_ERROR_IPC_FAILED));
+      embedded_worker_->Stop();
+      if (running_status() == EmbeddedWorkerStatus::STOPPED) {
+        RunSoon(base::BindOnce(callback, SERVICE_WORKER_OK));
         return;
       }
       stop_callbacks_.push_back(callback);
@@ -498,6 +494,7 @@
       RunSoon(base::BindOnce(callback, SERVICE_WORKER_OK));
       return;
   }
+  NOTREACHED();
 }
 
 void ServiceWorkerVersion::ScheduleUpdate() {
@@ -1858,8 +1855,9 @@
     // This worker is unresponsive and restart may fail.
     should_restart = false;
   } else if (old_status == EmbeddedWorkerStatus::STARTING) {
-    // This worker unexpectedly stopped because of start failure (e.g., process
-    // allocation failure) and restart is likely to fail again.
+    // This worker unexpectedly stopped because start failed.  Attempting to
+    // restart on start failure could cause an endless loop of start attempts,
+    // so don't try to restart now.
     should_restart = false;
   }
 
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 1f2ed7b..0f2da0d 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -123,6 +123,7 @@
 #include "content/browser/renderer_host/render_widget_host_view_android.h"
 #include "content/public/browser/android/child_process_importance.h"
 #include "content/test/mock_overscroll_refresh_handler_android.h"
+#include "ui/events/android/motion_event_android.h"
 #include "ui/gfx/geometry/point_f.h"
 #endif
 
@@ -11241,10 +11242,15 @@
                  ui::MotionEvent::Action action,
                  gfx::Point point) {
     DCHECK(action >= ui::MotionEvent::ACTION_DOWN &&
-           action << ui::MotionEvent::ACTION_CANCEL);
-    ui::MotionEventGeneric touch(
-        action, ui::EventTimeForNow(),
-        ui::PointerProperties(point.x(), point.y(), 10));
+           action < ui::MotionEvent::ACTION_CANCEL);
+
+    ui::MotionEventAndroid::Pointer p(0, point.x(), point.y(), 10, 0, 0, 0, 0);
+    JNIEnv* env = base::android::AttachCurrentThread();
+    auto time_ms = (ui::EventTimeForNow() - base::TimeTicks()).InMilliseconds();
+    ui::MotionEventAndroid touch(
+        env, nullptr, 1.f, 0, 0, 0, time_ms,
+        ui::MotionEventAndroid::GetAndroidActionForTesting(action), 1, 0, 0, 0,
+        0, 0, 0, 0, false, &p, nullptr);
     view->OnTouchEvent(touch);
   }
 };
diff --git a/content/browser/tracing/memory_tracing_browsertest.cc b/content/browser/tracing/memory_tracing_browsertest.cc
index cd8c492..edf0528 100644
--- a/content/browser/tracing/memory_tracing_browsertest.cc
+++ b/content/browser/tracing/memory_tracing_browsertest.cc
@@ -15,6 +15,7 @@
 #include "base/trace_event/memory_dump_request_args.h"
 #include "base/trace_event/trace_config_memory_test_util.h"
 #include "base/trace_event/trace_log.h"
+#include "build/build_config.h"
 #include "content/public/browser/tracing_controller.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test_utils.h"
@@ -305,8 +306,7 @@
 #endif  // !defined(GOOGLE_CHROME_BUILD)
 
 // Non-deterministic races under TSan. crbug.com/529678
-// Flaky on Linux. crbug.com/709524
-#if defined(THREAD_SANITIZER) || defined(OS_LINUX)
+#if defined(THREAD_SANITIZER)
 #define MAYBE_BrowserInitiatedDump DISABLED_BrowserInitiatedDump
 #else
 #define MAYBE_BrowserInitiatedDump BrowserInitiatedDump
@@ -317,7 +317,14 @@
   Navigate(shell());
 
   EXPECT_CALL(*mock_dump_provider_, OnMemoryDump(_,_)).WillOnce(Return(true));
+#if defined(OS_LINUX)
+  // TODO(ssid): Test for dump success once the on start tracing done callback
+  // is fixed to be called after enable tracing is acked by all processes,
+  // crbug.com/709524. The test still tests if dumping does not crash.
+  EXPECT_CALL(*this, OnMemoryDumpDone(_, _));
+#else
   EXPECT_CALL(*this, OnMemoryDumpDone(_, true /* success */));
+#endif
 
   EnableMemoryTracing();
   RequestGlobalDumpAndWait(false /* from_renderer_thread */,
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 959ff29a..ace18c5 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -1649,7 +1649,8 @@
 
   if (outer_web_contents_impl->frame_tree_.GetFocusedFrame() ==
       outer_contents_frame_impl->frame_tree_node()) {
-    SetFocusedFrame(frame_tree_.root(), nullptr);
+    SetFocusedFrame(frame_tree_.root(),
+                    outer_contents_frame->GetSiteInstance());
   }
 
   // Set up the the guest's AX tree to point back at the embedder's AX tree.
@@ -3464,12 +3465,6 @@
   const ResourceRedirectDetails& details) {
   for (auto& observer : observers_)
     observer.DidGetRedirectForResourceRequest(details);
-
-  // TODO(avi): Remove. http://crbug.com/170921
-  NotificationService::current()->Notify(
-      NOTIFICATION_RESOURCE_RECEIVED_REDIRECT,
-      Source<WebContents>(this),
-      Details<const ResourceRedirectDetails>(&details));
 }
 
 void WebContentsImpl::NotifyWebContentsFocused(
@@ -5268,14 +5263,36 @@
 
 void WebContentsImpl::SetFocusedFrame(FrameTreeNode* node,
                                       SiteInstance* source) {
-  SetAsFocusedWebContentsIfNecessary();
-
   frame_tree_.SetFocusedFrame(node, source);
 
-  WebContentsImpl* inner_contents = node_.GetInnerWebContentsInFrame(node);
-
-  WebContentsImpl* contents_to_focus = inner_contents ? inner_contents : this;
-  contents_to_focus->SetAsFocusedWebContentsIfNecessary();
+  if (auto* inner_contents = node_.GetInnerWebContentsInFrame(node)) {
+    // |this| is an outer WebContents and |node| represents an inner
+    // WebContents. Transfer the focus to the inner contents if |this| is
+    // focused.
+    if (GetFocusedWebContents() == this)
+      inner_contents->SetAsFocusedWebContentsIfNecessary();
+  } else if (node_.OuterContentsFrameTreeNode() &&
+             node_.OuterContentsFrameTreeNode()
+                     ->current_frame_host()
+                     ->GetSiteInstance() == source) {
+    // |this| is an inner WebContents, |node| is its main FrameTreeNode and
+    // the outer WebContents FrameTreeNode is at |source|'s SiteInstance.
+    // Transfer the focus to the inner WebContents if the outer WebContents is
+    // focused. This branch is used when an inner WebContents is focused through
+    // its RenderFrameProxyHost (via FrameHostMsg_FrameFocused IPC, used to
+    // implement the window.focus() API).
+    if (GetFocusedWebContents() == GetOuterWebContents())
+      SetAsFocusedWebContentsIfNecessary();
+  } else if (!GetOuterWebContents()) {
+    // This is an outermost WebContents.
+    SetAsFocusedWebContentsIfNecessary();
+  } else if (!GuestMode::IsCrossProcessFrameGuest(this) &&
+             GetOuterWebContents()) {
+    // TODO(lfg, paulmeyer): Allows BrowserPlugins to set themselves as the
+    // focused WebContents. This works around a bug in FindRequestManager that
+    // doesn't support properly traversing BrowserPlugins.
+    SetAsFocusedWebContentsIfNecessary();
+  }
 }
 
 RenderFrameHost* WebContentsImpl::GetFocusedFrameIncludingInnerWebContents() {
@@ -5302,6 +5319,18 @@
   }
 }
 
+void WebContentsImpl::OnAdvanceFocus(RenderFrameHostImpl* source_rfh) {
+  // When a RenderFrame needs to advance focus to a RenderFrameProxy (by hitting
+  // TAB), the RenderFrameProxy sends an IPC to RenderFrameProxyHost. When this
+  // RenderFrameProxyHost represents an inner WebContents, the outer WebContents
+  // needs to focus the inner WebContents.
+  if (GetOuterWebContents() &&
+      GetOuterWebContents() == source_rfh->delegate()->GetAsWebContents() &&
+      GetFocusedWebContents() == GetOuterWebContents()) {
+    SetAsFocusedWebContentsIfNecessary();
+  }
+}
+
 void WebContentsImpl::OnFocusedElementChangedInFrame(
     RenderFrameHostImpl* frame,
     const gfx::Rect& bounds_in_root_view) {
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index c9b0aa4..8484f67 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -549,6 +549,7 @@
   void OnFocusedElementChangedInFrame(
       RenderFrameHostImpl* frame,
       const gfx::Rect& bounds_in_root_view) override;
+  void OnAdvanceFocus(RenderFrameHostImpl* source_rfh) override;
   void CreateNewWindow(
       RenderFrameHost* opener,
       int32_t render_view_route_id,
diff --git a/content/browser/web_contents/web_contents_view_android.cc b/content/browser/web_contents/web_contents_view_android.cc
index 1947cd67..6e34c386 100644
--- a/content/browser/web_contents/web_contents_view_android.cc
+++ b/content/browser/web_contents/web_contents_view_android.cc
@@ -462,8 +462,7 @@
   web_contents_->GetRenderWidgetHostView()->Focus();
 }
 
-bool WebContentsViewAndroid::OnTouchEvent(const ui::MotionEventAndroid& event,
-                                          bool for_touch_handle) {
+bool WebContentsViewAndroid::OnTouchEvent(const ui::MotionEventAndroid& event) {
   if (event.GetAction() == ui::MotionEventAndroid::ACTION_DOWN)
     content_view_core_->OnTouchDown(event.GetJavaObject());
   return false;  // let the children handle the actual event.
diff --git a/content/browser/web_contents/web_contents_view_android.h b/content/browser/web_contents/web_contents_view_android.h
index dabecf2..26945c15 100644
--- a/content/browser/web_contents/web_contents_view_android.h
+++ b/content/browser/web_contents/web_contents_view_android.h
@@ -101,8 +101,7 @@
   void TakeFocus(bool reverse) override;
 
   // ui::ViewClient implementation.
-  bool OnTouchEvent(const ui::MotionEventAndroid& event,
-                    bool for_touch_handle) override;
+  bool OnTouchEvent(const ui::MotionEventAndroid& event) override;
   bool OnMouseEvent(const ui::MotionEventAndroid& event) override;
   bool OnDragEvent(const ui::DragEventAndroid& event) override;
   void OnPhysicalBackingSizeChanged() override;
diff --git a/content/child/service_worker/service_worker_dispatcher_unittest.cc b/content/child/service_worker/service_worker_dispatcher_unittest.cc
index 94a20b51..6d0d987d 100644
--- a/content/child/service_worker/service_worker_dispatcher_unittest.cc
+++ b/content/child/service_worker/service_worker_dispatcher_unittest.cc
@@ -11,8 +11,8 @@
 #include "content/child/service_worker/web_service_worker_impl.h"
 #include "content/child/service_worker/web_service_worker_registration_impl.h"
 #include "content/child/thread_safe_sender.h"
+#include "content/common/service_worker/service_worker_container.mojom.h"
 #include "content/common/service_worker/service_worker_messages.h"
-#include "content/common/service_worker/service_worker_provider_interfaces.mojom.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "ipc/ipc_sync_message_filter.h"
 #include "ipc/ipc_test_sink.h"
diff --git a/content/child/service_worker/service_worker_network_provider.cc b/content/child/service_worker/service_worker_network_provider.cc
index e400340..cd376b9 100644
--- a/content/child/service_worker/service_worker_network_provider.cc
+++ b/content/child/service_worker/service_worker_network_provider.cc
@@ -268,9 +268,9 @@
 
   ServiceWorkerProviderHostInfo host_info(
       browser_provider_id, route_id, provider_type, is_parent_frame_secure);
-  mojom::ServiceWorkerProviderAssociatedRequest client_request =
+  mojom::ServiceWorkerContainerAssociatedRequest client_request =
       mojo::MakeRequest(&host_info.client_ptr_info);
-  mojom::ServiceWorkerProviderHostAssociatedPtrInfo host_ptr_info;
+  mojom::ServiceWorkerContainerHostAssociatedPtrInfo host_ptr_info;
   host_info.host_request = mojo::MakeRequest(&host_ptr_info);
   DCHECK(host_info.host_request.is_pending());
   DCHECK(host_info.host_request.handle().is_valid());
diff --git a/content/child/service_worker/service_worker_provider_context.cc b/content/child/service_worker/service_worker_provider_context.cc
index c899f962..9b647c1 100644
--- a/content/child/service_worker/service_worker_provider_context.cc
+++ b/content/child/service_worker/service_worker_provider_context.cc
@@ -72,14 +72,14 @@
 ServiceWorkerProviderContext::ServiceWorkerProviderContext(
     int provider_id,
     ServiceWorkerProviderType provider_type,
-    mojom::ServiceWorkerProviderAssociatedRequest request,
-    mojom::ServiceWorkerProviderHostAssociatedPtrInfo host_ptr_info,
+    mojom::ServiceWorkerContainerAssociatedRequest request,
+    mojom::ServiceWorkerContainerHostAssociatedPtrInfo host_ptr_info,
     ServiceWorkerDispatcher* dispatcher,
     scoped_refptr<ChildURLLoaderFactoryGetter> default_loader_factory_getter)
     : provider_id_(provider_id),
       main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
       binding_(this, std::move(request)) {
-  provider_host_.Bind(std::move(host_ptr_info));
+  container_host_.Bind(std::move(host_ptr_info));
   if (provider_type == SERVICE_WORKER_PROVIDER_FOR_CONTROLLER) {
     controller_state_ = base::MakeUnique<ControllerState>();
   } else {
@@ -215,7 +215,7 @@
 }
 
 void ServiceWorkerProviderContext::OnNetworkProviderDestroyed() {
-  provider_host_.reset();
+  container_host_.reset();
 }
 
 void ServiceWorkerProviderContext::DestructOnMainThread() const {
diff --git a/content/child/service_worker/service_worker_provider_context.h b/content/child/service_worker/service_worker_provider_context.h
index 2a2083c5b0..f90538f3 100644
--- a/content/child/service_worker/service_worker_provider_context.h
+++ b/content/child/service_worker/service_worker_provider_context.h
@@ -13,8 +13,9 @@
 #include "content/child/child_url_loader_factory_getter.h"
 #include "content/child/service_worker/service_worker_dispatcher.h"
 #include "content/common/content_export.h"
+#include "content/common/service_worker/service_worker_container.mojom.h"
 #include "content/common/service_worker/service_worker_event_dispatcher.mojom.h"
-#include "content/common/service_worker/service_worker_provider_interfaces.mojom.h"
+#include "content/common/service_worker/service_worker_provider.mojom.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "mojo/public/cpp/bindings/associated_binding.h"
 
@@ -54,7 +55,7 @@
 class CONTENT_EXPORT ServiceWorkerProviderContext
     : public base::RefCountedThreadSafe<ServiceWorkerProviderContext,
                                         ServiceWorkerProviderContextDeleter>,
-      public mojom::ServiceWorkerProvider {
+      public mojom::ServiceWorkerContainer {
  public:
   // |provider_id| is used to identify this provider in IPC messages to the
   // browser process. |request| is an endpoint which is connected to
@@ -71,8 +72,8 @@
   ServiceWorkerProviderContext(
       int provider_id,
       ServiceWorkerProviderType provider_type,
-      mojom::ServiceWorkerProviderAssociatedRequest request,
-      mojom::ServiceWorkerProviderHostAssociatedPtrInfo host_ptr_info,
+      mojom::ServiceWorkerContainerAssociatedRequest request,
+      mojom::ServiceWorkerContainerHostAssociatedPtrInfo host_ptr_info,
       ServiceWorkerDispatcher* dispatcher,
       scoped_refptr<ChildURLLoaderFactoryGetter> default_loader_factory_getter);
 
@@ -152,9 +153,11 @@
   // Mojo binding for the |request| passed to the constructor. This keeps the
   // connection to the content::ServiceWorkerProviderHost in the browser process
   // alive.
-  mojo::AssociatedBinding<mojom::ServiceWorkerProvider> binding_;
-  // Browser-side Mojo endpoint for provider host.
-  mojom::ServiceWorkerProviderHostAssociatedPtr provider_host_;
+  mojo::AssociatedBinding<mojom::ServiceWorkerContainer> binding_;
+  // |container_host_| is the Mojo endpoint to the browser-side
+  // mojom::ServiceWorkerContainerHost that hosts this
+  // mojom::ServiceWorkerContainer.
+  mojom::ServiceWorkerContainerHostAssociatedPtr container_host_;
 
   // Either |controllee_state_| or |controller_state_| is non-null.
   std::unique_ptr<ControlleeState> controllee_state_;
diff --git a/content/child/service_worker/service_worker_provider_context_unittest.cc b/content/child/service_worker/service_worker_provider_context_unittest.cc
index 6925f50..ebfb14d 100644
--- a/content/child/service_worker/service_worker_provider_context_unittest.cc
+++ b/content/child/service_worker/service_worker_provider_context_unittest.cc
@@ -14,8 +14,8 @@
 #include "content/child/service_worker/web_service_worker_impl.h"
 #include "content/child/service_worker/web_service_worker_registration_impl.h"
 #include "content/child/thread_safe_sender.h"
+#include "content/common/service_worker/service_worker_container.mojom.h"
 #include "content/common/service_worker/service_worker_messages.h"
-#include "content/common/service_worker/service_worker_provider_interfaces.mojom.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "content/public/common/url_loader_factory.mojom.h"
 #include "ipc/ipc_sync_message_filter.h"
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index 119a5b751..6060e6eeb 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -628,10 +628,10 @@
     "renderer_host.mojom",
     "service_worker/embedded_worker.mojom",
     "service_worker/service_worker.mojom",
+    "service_worker/service_worker_container.mojom",
     "service_worker/service_worker_event_dispatcher.mojom",
     "service_worker/service_worker_installed_scripts_manager.mojom",
     "service_worker/service_worker_provider.mojom",
-    "service_worker/service_worker_provider_interfaces.mojom",
     "service_worker/service_worker_types.mojom",
     "storage_partition_service.mojom",
     "video_capture.mojom",
diff --git a/content/common/service_worker/service_worker.mojom b/content/common/service_worker/service_worker.mojom
index 476ac1e..334d46b 100644
--- a/content/common/service_worker/service_worker.mojom
+++ b/content/common/service_worker/service_worker.mojom
@@ -12,9 +12,9 @@
 // worker clients are created and when service workers are starting up.
 interface ServiceWorkerDispatcherHost {
   // Creates a content::ServiceWorkerProviderHost on the browser
-  // process. |provider_info| has Mojo endpoints to connect the provider host
-  // and the provider on the renderer together. The lifetime of
+  // process. |provider_info| has Mojo endpoints to connect the container host
+  // and the container on the renderer together. The lifetime of
   // ServiceWorkerProviderHost will be tied to the
-  // mojom::ServiceWorkerProviderHost interface.
+  // mojom::ServiceWorkerContainerHost interface.
   OnProviderCreated(ServiceWorkerProviderHostInfo provider_info);
 };
diff --git a/content/common/service_worker/service_worker_container.mojom b/content/common/service_worker/service_worker_container.mojom
new file mode 100644
index 0000000..4d4599e6
--- /dev/null
+++ b/content/common/service_worker/service_worker_container.mojom
@@ -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.
+
+module content.mojom;
+
+// mojom::ServiceWorkerContainerHost is a browser-side interface. The renderer
+// process uses this interface to request the browser process to do operations
+// involving service worker registrations.
+interface ServiceWorkerContainerHost {
+  // TODO(leon.han): implement them.
+  // Register();
+  // GetRegistation();
+  // GetRegistrations();
+  // GetRegistrationForReady();
+  // GetControllerServiceWorker();
+};
+
+// mojom::ServiceWorkerContainer is a renderer-side interface.
+// The browser process uses this interface to send messages to documents or
+// the service worker's context.
+//
+// Roughly corresponds to the web-exposed ServiceWorkerContainer interface,
+// i.e., navigator.serviceWorker. Actually, the plan is for this interface to be
+// used for anything that could access a ServiceWorkerRegistration or
+// ServiceWorker object. For example, ServiceWorkerGlobalScope needs to be
+// connected to this, since it has self.registration, even though we don’t
+// implement navigator.serviceWorker for Worker yet. But eventually anything
+// that can touch these objects should be a ServiceWorkerContainer, so it’s OK
+// to use this name.
+interface ServiceWorkerContainer {
+  // TODO(xiaofeng.zhang): implement them.
+  // SetController();
+  // ServiceWorkerStateChanged();
+  // ServiceWorkerRegistrationUpdateFound();
+  // PostMessage();
+};
diff --git a/content/common/service_worker/service_worker_provider.mojom b/content/common/service_worker/service_worker_provider.mojom
index 78aabe1..b74a1da 100644
--- a/content/common/service_worker/service_worker_provider.mojom
+++ b/content/common/service_worker/service_worker_provider.mojom
@@ -4,13 +4,13 @@
 
 module content.mojom;
 
-import "content/common/service_worker/service_worker_provider_interfaces.mojom";
+import "content/common/service_worker/service_worker_container.mojom";
 import "content/common/service_worker/service_worker_types.mojom";
 import "content/public/common/url_loader_factory.mojom";
 
-// A container object carried from the browser to the renderer process.
-// This contains the params for the constructor of ServiceWorkerNetworkProvider
-// used for starting a service worker.
+// Sent from the browser process to the renderer. Contains parameters for the
+// constructor of ServiceWorkerNetworkProvider used for starting a service
+// worker.
 struct ServiceWorkerProviderInfoForStartWorker {
   int32 provider_id;
   // |registration| and |attributes| are information about the service worker's
@@ -18,8 +18,8 @@
   ServiceWorkerRegistrationObjectInfo registration;
   ServiceWorkerVersionAttributes attributes;
 
-  associated ServiceWorkerProviderHost host_ptr_info;
-  associated ServiceWorkerProvider& client_request;
+  associated ServiceWorkerContainerHost host_ptr_info;
+  associated ServiceWorkerContainer& client_request;
 
   // For servicified service worker only.
   // The loader to use for loading the worker's main script and
@@ -27,8 +27,8 @@
   associated URLLoaderFactory? script_loader_factory_ptr_info;
 };
 
-// A container object carried from the renderer to the browser process.
-// This contains the parameters to specify the provider on the browser side.
+// Sent from the renderer to the browser process. Contains parameters that
+// describe a browser-side provider host.
 // See also comments in
 // content/common/service_worker/service_worker_provider_host_info.h.
 struct ServiceWorkerProviderHostInfo {
@@ -36,6 +36,24 @@
   int32 route_id;
   ServiceWorkerProviderType type;
   bool is_parent_frame_secure;
-  associated ServiceWorkerProviderHost& host_request;
-  associated ServiceWorkerProvider client_ptr_info;
+  associated ServiceWorkerContainerHost& host_request;
+  associated ServiceWorkerContainer client_ptr_info;
+};
+
+// ServiceWorkerWorkerClient represents a service worker client that is a worker
+// (i.e., a shared worker or dedicated worker). We use this interface to let the
+// WorkerFetchContextImpl in the worker thread know about the change of
+// controlling service worker by calling SetControllerServiceWorker() from the
+// ServiceWorkerProviderContext in the main thread of the renderer process.
+//
+// TODO(horo): We should implement ServiceWorkerProvider in the worker thread
+// instead of using this interface to support WorkerNavigator.serviceWorker
+// when we can make the worker thread totally independent from the main thread.
+// Currently we handle synchronous resource loading such as importScripts() and
+// synchronous XHR in the main thread. So we need to know whether the worker is
+// controlled by a service worker or not both in the main thread and in the
+// worker thread.
+interface ServiceWorkerWorkerClient {
+  // Called when the worker is controlled by a new service worker.
+  SetControllerServiceWorker(int64 controller_version_id);
 };
diff --git a/content/common/service_worker/service_worker_provider_host_info.cc b/content/common/service_worker/service_worker_provider_host_info.cc
index 23ac817..610dbb8 100644
--- a/content/common/service_worker/service_worker_provider_host_info.cc
+++ b/content/common/service_worker/service_worker_provider_host_info.cc
@@ -38,8 +38,8 @@
 
 ServiceWorkerProviderHostInfo::ServiceWorkerProviderHostInfo(
     ServiceWorkerProviderHostInfo&& other,
-    mojom::ServiceWorkerProviderHostAssociatedRequest host_request,
-    mojom::ServiceWorkerProviderAssociatedPtrInfo client_ptr_info)
+    mojom::ServiceWorkerContainerHostAssociatedRequest host_request,
+    mojom::ServiceWorkerContainerAssociatedPtrInfo client_ptr_info)
     : provider_id(other.provider_id),
       route_id(other.route_id),
       type(other.type),
diff --git a/content/common/service_worker/service_worker_provider_host_info.h b/content/common/service_worker/service_worker_provider_host_info.h
index e4418fa..68b05f9 100644
--- a/content/common/service_worker/service_worker_provider_host_info.h
+++ b/content/common/service_worker/service_worker_provider_host_info.h
@@ -5,19 +5,21 @@
 #ifndef CONTENT_COMMON_SERVICE_WORKER_SERVICE_WORKER_PROVIDER_HOST_INFO_H_
 #define CONTENT_COMMON_SERVICE_WORKER_SERVICE_WORKER_PROVIDER_HOST_INFO_H_
 
-#include "content/common/service_worker/service_worker_provider_interfaces.mojom.h"
+#include "content/common/service_worker/service_worker_container.mojom.h"
 #include "content/common/service_worker/service_worker_types.h"
 
 namespace content {
 
-// Container object to create a ServiceWorkerProviderHost.
+// ServiceWorkerProviderHostInfo contains params for creating a
+// ServiceWorkerProviderHost.
+// mojom::ServiceWorkerProviderHostInfo is mapped to this struct.
 struct CONTENT_EXPORT ServiceWorkerProviderHostInfo {
   ServiceWorkerProviderHostInfo();
   ServiceWorkerProviderHostInfo(ServiceWorkerProviderHostInfo&& other);
   ServiceWorkerProviderHostInfo(
       ServiceWorkerProviderHostInfo&& other,
-      mojom::ServiceWorkerProviderHostAssociatedRequest host_request,
-      mojom::ServiceWorkerProviderAssociatedPtrInfo client_ptr_info);
+      mojom::ServiceWorkerContainerHostAssociatedRequest host_request,
+      mojom::ServiceWorkerContainerAssociatedPtrInfo client_ptr_info);
   ServiceWorkerProviderHostInfo(int provider_id,
                                 int route_id,
                                 ServiceWorkerProviderType type,
@@ -57,14 +59,14 @@
   // will be associated with ServiceWorkerDisptacherHost. |host_request| should
   // be valid when ServiceWorkerProviderHostInfo is passed to any Mojo methods.
   // After used to create the ServiceWorkerProviderHost, this will be invalid.
-  mojom::ServiceWorkerProviderHostAssociatedRequest host_request;
+  mojom::ServiceWorkerContainerHostAssociatedRequest host_request;
 
   // Mojo endpoint to send a message from the browser to the renderer. This
   // will be associated with ServiceWorkerDisptacherHost. |client_ptr_info|
   // should be valid when ServiceWorkerProviderHostInfo is passed to any Mojo
   // methods.
   // After used to create the ServiceWorkerProviderHost, this will be invalid.
-  mojom::ServiceWorkerProviderAssociatedPtrInfo client_ptr_info;
+  mojom::ServiceWorkerContainerAssociatedPtrInfo client_ptr_info;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(ServiceWorkerProviderHostInfo);
diff --git a/content/common/service_worker/service_worker_provider_interfaces.mojom b/content/common/service_worker/service_worker_provider_interfaces.mojom
deleted file mode 100644
index fbec377..0000000
--- a/content/common/service_worker/service_worker_provider_interfaces.mojom
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module content.mojom;
-
-// ServiceWorkerWorkerClient represents a service worker client that is a worker
-// (i.e., a shared worker or dedicated worker). We use this interface to let the
-// WorkerFetchContextImpl in the worker thread know about the change of
-// controlling service worker by calling SetControllerServiceWorker() from the
-// ServiceWorkerProviderContext in the main thread of the renderer process.
-//
-// TODO(horo): We should implement ServiceWorkerProvider in the worker thread
-// instead of using this interface to support WorkerNavigator.serviceWorker
-// when we can make the worker thread totally independent from the main thread.
-// Currently we handle synchronous resource loading such as importScripts() and
-// synchronous XHR in the main thread. So We need to know whether the worker is
-// controlled by a service worker or not both in the main thread and in the
-// worker thread.
-interface ServiceWorkerWorkerClient {
-  // Called when the worker is controlled by a new service worker.
-  SetControllerServiceWorker(int64 controller_version_id);
-};
-
-// mojom::ServiceWorkerProviderHost is a browser-side interface. The renderer
-// uses this interface to request the browser to do operations involving service
-// worker registrations.
-interface ServiceWorkerProviderHost {
-  // TODO(shimazu): implement them.
-  // register() => ();
-  // getRegistation() => ();
-  // getRegistrations() => ();
-  // getRegistrationForReady() => ();
-};
-
-// mojom::ServiceWorkerProvider is a renderer-side interface.
-// The browser process uses this interface to send messages to pages or
-// the service worker's context.
-interface ServiceWorkerProvider {
-  // TODO(shimazu): implement them.
-  // associateRegistration();
-  // disassociateRegistration();
-  // setControllerServiceWorker();
-  // messageToDocument();
-};
diff --git a/content/common/service_worker/service_worker_provider_struct_traits.cc b/content/common/service_worker/service_worker_provider_struct_traits.cc
index 5202e30..a94ecaa 100644
--- a/content/common/service_worker/service_worker_provider_struct_traits.cc
+++ b/content/common/service_worker/service_worker_provider_struct_traits.cc
@@ -17,9 +17,9 @@
   out->route_id = in.route_id();
   out->is_parent_frame_secure = in.is_parent_frame_secure();
   out->host_request = in.TakeHostRequest<
-      content::mojom::ServiceWorkerProviderHostAssociatedRequest>();
+      content::mojom::ServiceWorkerContainerHostAssociatedRequest>();
   out->client_ptr_info = in.TakeClientPtrInfo<
-      content::mojom::ServiceWorkerProviderAssociatedPtrInfo>();
+      content::mojom::ServiceWorkerContainerAssociatedPtrInfo>();
   return true;
 }
 
diff --git a/content/common/service_worker/service_worker_provider_struct_traits.h b/content/common/service_worker/service_worker_provider_struct_traits.h
index bdab91f..11de120 100644
--- a/content/common/service_worker/service_worker_provider_struct_traits.h
+++ b/content/common/service_worker/service_worker_provider_struct_traits.h
@@ -31,12 +31,12 @@
     return info.is_parent_frame_secure;
   }
 
-  static content::mojom::ServiceWorkerProviderHostAssociatedRequest&
+  static content::mojom::ServiceWorkerContainerHostAssociatedRequest&
   host_request(content::ServiceWorkerProviderHostInfo& info) {
     return info.host_request;
   }
 
-  static content::mojom::ServiceWorkerProviderAssociatedPtrInfo&
+  static content::mojom::ServiceWorkerContainerAssociatedPtrInfo&
   client_ptr_info(content::ServiceWorkerProviderHostInfo& info) {
     return info.client_ptr_info;
   }
diff --git a/content/gpu/gpu_child_thread.cc b/content/gpu/gpu_child_thread.cc
index dad6fc5..d9de3c3c 100644
--- a/content/gpu/gpu_child_thread.cc
+++ b/content/gpu/gpu_child_thread.cc
@@ -206,8 +206,8 @@
   registry->AddInterface(base::Bind(&GpuChildThread::BindServiceFactoryRequest,
                                     weak_factory_.GetWeakPtr()),
                          base::ThreadTaskRunnerHandle::Get());
-  if (GetContentClient()->gpu())  // NULL in tests.
-    GetContentClient()->gpu()->Initialize(registry.get());
+  if (GetContentClient()->gpu())  // nullptr in tests.
+    GetContentClient()->gpu()->InitializeRegistry(registry.get());
 
   std::unique_ptr<QueueingConnectionFilter> filter =
       base::MakeUnique<QueueingConnectionFilter>(GetIOTaskRunner(),
diff --git a/content/gpu/in_process_gpu_thread.cc b/content/gpu/in_process_gpu_thread.cc
index 291a524c..bd6c1f6c 100644
--- a/content/gpu/in_process_gpu_thread.cc
+++ b/content/gpu/in_process_gpu_thread.cc
@@ -9,7 +9,9 @@
 #include "build/build_config.h"
 #include "content/gpu/gpu_child_thread.h"
 #include "content/gpu/gpu_process.h"
+#include "content/public/common/content_client.h"
 #include "content/public/common/content_switches.h"
+#include "content/public/gpu/content_gpu_client.h"
 #include "gpu/config/gpu_info_collector.h"
 #include "gpu/config/gpu_util.h"
 #include "ui/gl/init/gl_factory.h"
@@ -55,16 +57,22 @@
 #endif
 
   gpu::GPUInfo gpu_info;
+  gpu::GpuFeatureInfo gpu_feature_info;
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
   if (!gl::init::InitializeGLOneOff()) {
     VLOG(1) << "gl::init::InitializeGLOneOff failed";
-  } else {
-    if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
-            switches::kSkipGpuDataLoading))
-      gpu::CollectContextGraphicsInfo(&gpu_info);
+  } else if (GetContentClient()->gpu() &&
+             GetContentClient()->gpu()->GetGPUInfo() &&
+             GetContentClient()->gpu()->GetGpuFeatureInfo()) {
+    gpu_info = *(GetContentClient()->gpu()->GetGPUInfo());
+    gpu_feature_info = *(GetContentClient()->gpu()->GetGpuFeatureInfo());
+  } else if (!command_line->HasSwitch(switches::kSkipGpuDataLoading)) {
+    // TODO(zmo): No need to initialize bindings again inside
+    // CollectContextGraphicsInfo().
+    gpu::CollectContextGraphicsInfo(&gpu_info);
+    gpu_feature_info = gpu::GetGpuFeatureInfo(gpu_info, *command_line);
   }
-
-  gpu::GpuFeatureInfo gpu_feature_info =
-      gpu::GetGpuFeatureInfo(gpu_info, *base::CommandLine::ForCurrentProcess());
+  GetContentClient()->SetGpuInfo(gpu_info);
 
   // The process object takes ownership of the thread object, so do not
   // save and delete the pointer.
diff --git a/content/public/android/BUILD.gn b/content/public/android/BUILD.gn
index 6daa0be..8d00be85 100644
--- a/content/public/android/BUILD.gn
+++ b/content/public/android/BUILD.gn
@@ -114,7 +114,6 @@
     "java/src/org/chromium/content/browser/ChildProcessCreationParams.java",
     "java/src/org/chromium/content/browser/ChildProcessLauncherHelper.java",
     "java/src/org/chromium/content/browser/ContentChildProcessConstants.java",
-    "java/src/org/chromium/content/browser/ContentClassFactory.java",
     "java/src/org/chromium/content/browser/ContentFeatureList.java",
     "java/src/org/chromium/content/browser/ContentNfcDelegate.java",
     "java/src/org/chromium/content/browser/ContentVideoView.java",
@@ -234,6 +233,7 @@
     "java/src/org/chromium/content_public/browser/ScreenOrientationDelegate.java",
     "java/src/org/chromium/content_public/browser/ScreenOrientationDelegateManager.java",
     "java/src/org/chromium/content_public/browser/SmartClipCallback.java",
+    "java/src/org/chromium/content_public/browser/SmartSelectionToggle.java",
     "java/src/org/chromium/content_public/browser/WebContents.java",
     "java/src/org/chromium/content_public/browser/WebContentsObserver.java",
     "java/src/org/chromium/content_public/browser/WebContentsStatics.java",
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentClassFactory.java b/content/public/android/java/src/org/chromium/content/browser/ContentClassFactory.java
deleted file mode 100644
index c52e4f57..0000000
--- a/content/public/android/java/src/org/chromium/content/browser/ContentClassFactory.java
+++ /dev/null
@@ -1,48 +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.
-
-package org.chromium.content.browser;
-
-import org.chromium.base.ThreadUtils;
-import org.chromium.ui.base.WindowAndroid;
-
-/**
- * A class factory for content browser layer.
- */
-public class ContentClassFactory {
-    private static ContentClassFactory sSingleton;
-
-    /**
-     * Sets the factory object.
-     */
-    public static void set(ContentClassFactory factory) {
-        ThreadUtils.assertOnUiThread();
-
-        sSingleton = factory;
-    }
-
-    /**
-     * Returns the factory object.
-     */
-    public static ContentClassFactory get() {
-        ThreadUtils.assertOnUiThread();
-
-        if (sSingleton == null) sSingleton = new ContentClassFactory();
-        return sSingleton;
-    }
-
-    /**
-     * Constructor.
-     */
-    protected ContentClassFactory() {}
-
-    /**
-     * Creates SmartSelectorProvider object.
-     */
-    public SmartSelectionProvider createSmartSelectionProvider(
-            SmartSelectionProvider.ResultCallback callback, WindowAndroid windowAndroid) {
-        // Implemented by a subclass.
-        return null;
-    }
-}
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 4d9fa343..665a4788 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
@@ -30,6 +30,7 @@
 import android.view.accessibility.AccessibilityNodeProvider;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
+import android.view.textclassifier.TextClassifier;
 
 import org.chromium.base.ObserverList;
 import org.chromium.base.ObserverList.RewindableIterator;
@@ -2131,29 +2132,26 @@
         mSelectionPopupController.setSelectionClient(selectionClient);
     }
 
-    // TODO(timav): Use |TextClassifier| instead of |Object| after we switch to Android SDK 26.
     /**
      * Sets TextClassifier for Smart Text selection.
      */
-    public void setTextClassifier(Object textClassifier) {
+    public void setTextClassifier(TextClassifier textClassifier) {
         mSelectionPopupController.setTextClassifier(textClassifier);
     }
 
-    // TODO(timav): Use |TextClassifier| instead of |Object| after we switch to Android SDK 26.
     /**
      * Returns TextClassifier that is used for Smart Text selection. If the custom classifier
      * has been set with setTextClassifier, returns that object, otherwise returns the system
      * classifier.
      */
-    public Object getTextClassifier() {
+    public TextClassifier getTextClassifier() {
         return mSelectionPopupController.getTextClassifier();
     }
 
-    // TODO(timav): Use |TextClassifier| instead of |Object| after we switch to Android SDK 26.
     /**
      * Returns the TextClassifier which has been set with setTextClassifier(), or null.
      */
-    public Object getCustomTextClassifier() {
+    public TextClassifier getCustomTextClassifier() {
         return mSelectionPopupController.getCustomTextClassifier();
     }
 
diff --git a/content/public/android/java/src/org/chromium/content/browser/SelectionClient.java b/content/public/android/java/src/org/chromium/content/browser/SelectionClient.java
index a9c63b7..6194573 100644
--- a/content/public/android/java/src/org/chromium/content/browser/SelectionClient.java
+++ b/content/public/android/java/src/org/chromium/content/browser/SelectionClient.java
@@ -4,6 +4,8 @@
 
 package org.chromium.content.browser;
 
+import android.view.textclassifier.TextClassifier;
+
 /**
  * Interface to a content layer client that can process and modify selection text.
  */
@@ -56,17 +58,17 @@
      * Sets TextClassifier for the Smart Text selection. Pass null argument to use the system
      * classifier
      */
-    public void setTextClassifier(Object textClassifier);
+    public void setTextClassifier(TextClassifier textClassifier);
 
     /**
      * Gets TextClassifier that is used for the Smart Text selection. If the custom classifier
      * has been set with setTextClassifier, returns that object, otherwise returns the system
      * classifier.
      */
-    public Object getTextClassifier();
+    public TextClassifier getTextClassifier();
 
     /**
      * Returns the TextClassifier which has been set with setTextClassifier(), or null.
      */
-    public Object getCustomTextClassifier();
+    public TextClassifier getCustomTextClassifier();
 }
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 d70097a..10fb514 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
@@ -30,6 +30,7 @@
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.WindowManager;
+import android.view.textclassifier.TextClassifier;
 
 import org.chromium.base.BuildInfo;
 import org.chromium.base.Log;
@@ -136,9 +137,6 @@
     // SmartSelectionProvider was able to classify it, otherwise null.
     private SmartSelectionProvider.Result mClassificationResult;
 
-    // The resource ID for Assist menu item.
-    private int mAssistMenuItemId;
-
     // This variable is set to true when showActionMode() is postponed till classification result
     // arrives or till the selection is adjusted based on the classification result.
     private boolean mPendingShowActionMode;
@@ -179,12 +177,6 @@
                 SmartSelectionClient.create(new SmartSelectionCallback(), window, webContents);
 
         mLastSelectedText = "";
-        // TODO(timav): Use android.R.id.textAssist for the Assist item id once we switch to
-        // Android O SDK and remove |mAssistMenuItemId|.
-        if (BuildInfo.isAtLeastO()) {
-            mAssistMenuItemId =
-                    mContext.getResources().getIdentifier("textAssist", "id", "android");
-        }
 
         nativeInit(webContents);
     }
@@ -609,16 +601,10 @@
 
     private void updateAssistMenuItem(MenuDescriptor descriptor) {
         // There is no Assist functionality before Android O.
-        if (!BuildInfo.isAtLeastO() || mAssistMenuItemId == 0) return;
-
-        // The assist menu item ID has to be equal to android.R.id.textAssist. Until we compile
-        // with Android O SDK where this ID is defined we replace the corresponding inflated
-        // item with an item with the proper ID.
-        // TODO(timav): Use android.R.id.textAssist for the Assist item id once we switch to
-        // Android O SDK and remove |mAssistMenuItemId|.
+        if (!BuildInfo.isAtLeastO()) return;
 
         if (mClassificationResult != null && mClassificationResult.hasNamedAction()) {
-            descriptor.addItem(R.id.select_action_menu_assist_items, mAssistMenuItemId, 1,
+            descriptor.addItem(R.id.select_action_menu_assist_items, android.R.id.textAssist, 1,
                     mClassificationResult.label, mClassificationResult.icon);
         }
     }
@@ -665,7 +651,7 @@
         int id = item.getItemId();
         int groupId = item.getGroupId();
 
-        if (BuildInfo.isAtLeastO() && id == mAssistMenuItemId) {
+        if (BuildInfo.isAtLeastO()) {
             doAssistAction();
             mode.finish();
         } else if (id == R.id.select_action_menu_select_all) {
@@ -1131,29 +1117,26 @@
                 PackageManager.MATCH_DEFAULT_ONLY).size() > 0;
     }
 
-    // TODO(timav): Use |TextClassifier| instead of |Object| after we switch to Android SDK 26.
     /**
      * Sets TextClassifier for Smart Text selection.
      */
-    public void setTextClassifier(Object textClassifier) {
+    public void setTextClassifier(TextClassifier textClassifier) {
         if (mSelectionClient != null) mSelectionClient.setTextClassifier(textClassifier);
     }
 
-    // TODO(timav): Use |TextClassifier| instead of |Object| after we switch to Android SDK 26.
     /**
      * Returns TextClassifier that is used for Smart Text selection. If the custom classifier
      * has been set with setTextClassifier, returns that object, otherwise returns the system
      * classifier.
      */
-    public Object getTextClassifier() {
+    public TextClassifier getTextClassifier() {
         return mSelectionClient == null ? null : mSelectionClient.getTextClassifier();
     }
 
-    // TODO(timav): Use |TextClassifier| instead of |Object| after we switch to Android SDK 26.
     /**
      * Returns the TextClassifier which has been set with setTextClassifier(), or null.
      */
-    public Object getCustomTextClassifier() {
+    public TextClassifier getCustomTextClassifier() {
         return mSelectionClient == null ? null : mSelectionClient.getCustomTextClassifier();
     }
 
diff --git a/content/public/android/java/src/org/chromium/content/browser/SmartSelectionClient.java b/content/public/android/java/src/org/chromium/content/browser/SmartSelectionClient.java
index 1990bca..3a5e9937 100644
--- a/content/public/android/java/src/org/chromium/content/browser/SmartSelectionClient.java
+++ b/content/public/android/java/src/org/chromium/content/browser/SmartSelectionClient.java
@@ -6,6 +6,7 @@
 
 import android.support.annotation.IntDef;
 import android.text.TextUtils;
+import android.view.textclassifier.TextClassifier;
 
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
@@ -39,22 +40,25 @@
     // Used for surrounding text request.
     private static final int NUM_EXTRA_CHARS = 240;
 
+    // Is smart selection enabled?
+    private static boolean sEnabled;
+
     private long mNativeSmartSelectionClient;
     private SmartSelectionProvider mProvider;
     private SmartSelectionProvider.ResultCallback mCallback;
 
+    public static void setEnabled(boolean enabled) {
+        sEnabled = enabled;
+    }
+
     /**
      * Creates the SmartSelectionClient. Returns null in case SmartSelectionProvider does not exist
      * in the system.
      */
     public static SmartSelectionClient create(SmartSelectionProvider.ResultCallback callback,
             WindowAndroid windowAndroid, WebContents webContents) {
-        SmartSelectionProvider provider =
-                ContentClassFactory.get().createSmartSelectionProvider(callback, windowAndroid);
-
-        // SmartSelectionProvider might not exist.
-        if (provider == null) return null;
-
+        if (!sEnabled) return null;
+        SmartSelectionProvider provider = new SmartSelectionProvider(callback, windowAndroid);
         return new SmartSelectionClient(provider, callback, webContents);
     }
 
@@ -100,21 +104,18 @@
         mProvider.cancelAllRequests();
     }
 
-    // TODO(timav): Use |TextClassifier| instead of |Object| after we switch to Android SDK 26.
     @Override
-    public void setTextClassifier(Object textClassifier) {
+    public void setTextClassifier(TextClassifier textClassifier) {
         mProvider.setTextClassifier(textClassifier);
     }
 
-    // TODO(timav): Use |TextClassifier| instead of |Object| after we switch to Android SDK 26.
     @Override
-    public Object getTextClassifier() {
+    public TextClassifier getTextClassifier() {
         return mProvider.getTextClassifier();
     }
 
-    // TODO(timav): Use |TextClassifier| instead of |Object| after we switch to Android SDK 26.
     @Override
-    public Object getCustomTextClassifier() {
+    public TextClassifier getCustomTextClassifier() {
         return mProvider.getCustomTextClassifier();
     }
 
diff --git a/content/public/android/java/src/org/chromium/content/browser/SmartSelectionProvider.java b/content/public/android/java/src/org/chromium/content/browser/SmartSelectionProvider.java
index 427a388..80cb3b3 100644
--- a/content/public/android/java/src/org/chromium/content/browser/SmartSelectionProvider.java
+++ b/content/public/android/java/src/org/chromium/content/browser/SmartSelectionProvider.java
@@ -4,19 +4,30 @@
 
 package org.chromium.content.browser;
 
+import android.annotation.SuppressLint;
+import android.content.Context;
 import android.content.Intent;
 import android.graphics.drawable.Drawable;
+import android.os.AsyncTask;
+import android.os.Handler;
+import android.os.LocaleList;
+import android.support.annotation.IntDef;
 import android.view.View.OnClickListener;
+import android.view.textclassifier.TextClassification;
+import android.view.textclassifier.TextClassificationManager;
+import android.view.textclassifier.TextClassifier;
+import android.view.textclassifier.TextSelection;
 
-import org.chromium.base.annotations.SuppressFBWarnings;
+import org.chromium.ui.base.WindowAndroid;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Locale;
 
 /**
- * The interface that controls Smart Text selection.
+ * Controls Smart Text selection. Talks to the Android TextClassificationManager API.
  */
-@SuppressFBWarnings("UUF_UNUSED_PUBLIC_OR_PROTECTED_FIELD")
-public interface SmartSelectionProvider {
+public class SmartSelectionProvider {
     /**
      * The result of the text analysis.
      */
@@ -72,48 +83,148 @@
         void onClassified(Result result);
     }
 
-    /**
-     * Sends asynchronous request to obtain the selection, analyze its type and suggest
-     * better selection boundaries.
-     * @param text  The textual context that encloses the selected text.
-     * @param start The start index of the selected text inside the textual context.
-     * @param end   The index pointing to the first character that comes after
-     *              the selected text inside the textual context.
-     */
+    private static final String TAG = "SmartSelProvider";
+
+    @IntDef({CLASSIFY, SUGGEST_AND_CLASSIFY})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface RequestType {}
+
+    private static final int CLASSIFY = 0;
+    private static final int SUGGEST_AND_CLASSIFY = 1;
+
+    private ResultCallback mResultCallback;
+    private WindowAndroid mWindowAndroid;
+    private ClassificationTask mClassificationTask;
+    private TextClassifier mTextClassifier;
+
+    private Handler mHandler;
+    private Runnable mFailureResponseRunnable;
+
+    public SmartSelectionProvider(ResultCallback callback, WindowAndroid windowAndroid) {
+        mResultCallback = callback;
+        mWindowAndroid = windowAndroid;
+        mHandler = new Handler();
+        mFailureResponseRunnable = new Runnable() {
+            @Override
+            public void run() {
+                mResultCallback.onClassified(new Result());
+            }
+        };
+    }
+
     public void sendSuggestAndClassifyRequest(
-            CharSequence text, int start, int end, Locale[] locales);
+            CharSequence text, int start, int end, Locale[] locales) {
+        sendSmartSelectionRequest(SUGGEST_AND_CLASSIFY, text, start, end, locales);
+    }
 
-    /**
-     * Sends asynchronous request to obtain the selection and analyze its type.
-     * @param text  The textual context that encloses the selected text.
-     * @param start The start index of the selected text inside the textual context.
-     * @param end   The index pointing to the first character that comes after
-     *              the selected text inside the textual context.
-     */
-    public void sendClassifyRequest(CharSequence text, int start, int end, Locale[] locales);
+    public void sendClassifyRequest(CharSequence text, int start, int end, Locale[] locales) {
+        sendSmartSelectionRequest(CLASSIFY, text, start, end, locales);
+    }
 
-    /**
-     * Cancel all asynchronous requests.
-     */
-    public void cancelAllRequests();
+    public void cancelAllRequests() {
+        if (mClassificationTask != null) {
+            mClassificationTask.cancel(false);
+            mClassificationTask = null;
+        }
+    }
 
-    // TODO(timav): Use |TextClassifier| instead of |Object| after we switch to Android SDK 26.
-    /**
-     * Sets TextClassifier for Smart Text selection.
-     */
-    public void setTextClassifier(Object textClassifier);
+    public void setTextClassifier(TextClassifier textClassifier) {
+        mTextClassifier = textClassifier;
+    }
 
-    // TODO(timav): Use |TextClassifier| instead of |Object| after we switch to Android SDK 26.
-    /**
-     * Returns TextClassifier used for Smart Text selection.
-     * If the user sets non-null text classifier object, returns that object. Otherwise returns
-     * the system classifier obtained from the TextClassificationManager service.
-     */
-    public Object getTextClassifier();
+    // TODO(crbug.com/739746): Remove suppression when this constant is added to lint.
+    @SuppressLint("WrongConstant")
+    public TextClassifier getTextClassifier() {
+        if (mTextClassifier != null) return mTextClassifier;
 
-    // TODO(timav): Use |TextClassifier| instead of |Object| after we switch to Android SDK 26.
-    /**
-     * Returns TextClassifier object if the one has been set with setTextClassifier(), or null.
-     */
-    public Object getCustomTextClassifier();
+        Context context = mWindowAndroid.getContext().get();
+        if (context == null) return null;
+
+        return ((TextClassificationManager) context.getSystemService(
+                        Context.TEXT_CLASSIFICATION_SERVICE))
+                .getTextClassifier();
+    }
+
+    public TextClassifier getCustomTextClassifier() {
+        return mTextClassifier;
+    }
+
+    private void sendSmartSelectionRequest(
+            @RequestType int requestType, CharSequence text, int start, int end, Locale[] locales) {
+        TextClassifier classifier = (TextClassifier) getTextClassifier();
+        if (classifier == null || classifier == TextClassifier.NO_OP) {
+            mHandler.post(mFailureResponseRunnable);
+            return;
+        }
+
+        if (mClassificationTask != null) {
+            mClassificationTask.cancel(false);
+            mClassificationTask = null;
+        }
+
+        mClassificationTask =
+                new ClassificationTask(classifier, requestType, text, start, end, locales);
+        mClassificationTask.execute();
+    }
+
+    private class ClassificationTask extends AsyncTask<Void, Void, Result> {
+        private final TextClassifier mTextClassifier;
+        private final int mRequestType;
+        private final CharSequence mText;
+        private final int mOriginalStart;
+        private final int mOriginalEnd;
+        private final Locale[] mLocales;
+
+        ClassificationTask(TextClassifier classifier, @RequestType int requestType,
+                CharSequence text, int start, int end, Locale[] locales) {
+            mTextClassifier = classifier;
+            mRequestType = requestType;
+            mText = text;
+            mOriginalStart = start;
+            mOriginalEnd = end;
+            mLocales = locales;
+        }
+
+        @Override
+        protected Result doInBackground(Void... params) {
+            int start = mOriginalStart;
+            int end = mOriginalEnd;
+
+            if (mRequestType == SUGGEST_AND_CLASSIFY) {
+                TextSelection suggested = mTextClassifier.suggestSelection(
+                        mText, start, end, makeLocaleList(mLocales));
+                start = Math.max(0, suggested.getSelectionStartIndex());
+                end = Math.min(mText.length(), suggested.getSelectionEndIndex());
+                if (isCancelled()) return new Result();
+            }
+
+            TextClassification tc =
+                    mTextClassifier.classifyText(mText, start, end, makeLocaleList(mLocales));
+            return makeResult(start, end, tc);
+        }
+
+        @SuppressLint("NewApi")
+        private LocaleList makeLocaleList(Locale[] locales) {
+            if (locales == null || locales.length == 0) return null;
+            return new LocaleList(locales);
+        }
+
+        private Result makeResult(int start, int end, TextClassification tc) {
+            Result result = new Result();
+
+            result.startAdjust = start - mOriginalStart;
+            result.endAdjust = end - mOriginalEnd;
+            result.label = tc.getLabel();
+            result.icon = tc.getIcon();
+            result.intent = tc.getIntent();
+            result.onClickListener = tc.getOnClickListener();
+
+            return result;
+        }
+
+        @Override
+        protected void onPostExecute(Result result) {
+            mResultCallback.onClassified(result);
+        }
+    }
 }
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/SuggestionsPopupWindow.java b/content/public/android/java/src/org/chromium/content/browser/input/SuggestionsPopupWindow.java
index d84ff94b..4919d11 100644
--- a/content/public/android/java/src/org/chromium/content/browser/input/SuggestionsPopupWindow.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/SuggestionsPopupWindow.java
@@ -41,6 +41,9 @@
             "com.android.settings.USER_DICTIONARY_INSERT";
     private static final String USER_DICTIONARY_EXTRA_WORD = "word";
 
+    // From Android Settings app's @integer/maximum_user_dictionary_word_length.
+    private static final int ADD_TO_DICTIONARY_MAX_LENGTH_ON_JELLY_BEAN = 48;
+
     private final Context mContext;
     private final TextSuggestionHost mTextSuggestionHost;
     private final View mParentView;
@@ -167,7 +170,23 @@
 
     private void addToDictionary() {
         final Intent intent = new Intent(ACTION_USER_DICTIONARY_INSERT);
-        intent.putExtra(USER_DICTIONARY_EXTRA_WORD, mHighlightedText);
+
+        String wordToAdd = mHighlightedText;
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
+            // There was a bug in Jelly Bean, fixed in the initial version of KitKat, that can cause
+            // a crash if the word we try to add is too long. The "add to dictionary" intent uses an
+            // EditText widget to show the word about to be added (and allow the user to edit it).
+            // It has a maximum length of 48 characters. If a word is longer than this, it will be
+            // truncated, but the intent will try to select the full length of the word, causing a
+            // crash.
+
+            // KitKit and later still truncate the word, but avoid the crash.
+            if (wordToAdd.length() > ADD_TO_DICTIONARY_MAX_LENGTH_ON_JELLY_BEAN) {
+                wordToAdd = wordToAdd.substring(0, ADD_TO_DICTIONARY_MAX_LENGTH_ON_JELLY_BEAN);
+            }
+        }
+
+        intent.putExtra(USER_DICTIONARY_EXTRA_WORD, wordToAdd);
         intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
         mContext.startActivity(intent);
     }
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/SmartSelectionToggle.java b/content/public/android/java/src/org/chromium/content_public/browser/SmartSelectionToggle.java
new file mode 100644
index 0000000..aaede14
--- /dev/null
+++ b/content/public/android/java/src/org/chromium/content_public/browser/SmartSelectionToggle.java
@@ -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.
+
+package org.chromium.content_public.browser;
+
+import org.chromium.content.browser.SmartSelectionClient;
+
+/**
+ * A public API to enable/disable smart selection. The default is disabled.
+ */
+public class SmartSelectionToggle {
+    public static void setEnabled(boolean enabled) {
+        SmartSelectionClient.setEnabled(enabled);
+    }
+}
diff --git a/content/public/browser/notification_types.h b/content/public/browser/notification_types.h
index e1348b6e..260ba432 100644
--- a/content/public/browser/notification_types.h
+++ b/content/public/browser/notification_types.h
@@ -65,12 +65,6 @@
   // DEPRECATED: Use WebContentsObserver::DidStopLoading()
   NOTIFICATION_LOAD_STOP,
 
-  // A redirect was received while requesting a resource.  The source will be
-  // a Source<WebContents> corresponding to the tab in which the request was
-  // issued.  Details in the form of a ResourceRedirectDetails are provided.
-  // DEPRECATED: Use WebContentsObserver::DidGetRedirectForResourceRequest()
-  NOTIFICATION_RESOURCE_RECEIVED_REDIRECT,
-
   // WebContents ---------------------------------------------------------------
 
   // This notification is sent when a render view host has connected to a
@@ -130,14 +124,6 @@
   // painted. The source is the RenderWidgetHost, the details are not used.
   NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
 
-  // Sent from RenderViewHost::ClosePage.  The hosted RenderView has
-  // processed the onbeforeunload handler and is about to be sent a
-  // ViewMsg_ClosePage message to complete the tear-down process.  The source
-  // is the RenderViewHost sending the message, and no details are provided.
-  // Note:  This message is not sent in response to RenderView closure
-  // initiated by window.close().
-  NOTIFICATION_RENDER_VIEW_HOST_WILL_CLOSE_RENDER_VIEW,
-
   // Indicates a RenderWidgetHost has been hidden or restored. The source is
   // the RWH whose visibility changed, the details is a bool set to true if
   // the new state is "visible."
diff --git a/content/public/browser/permission_type.h b/content/public/browser/permission_type.h
index 22b3c3b..876eec5278 100644
--- a/content/public/browser/permission_type.h
+++ b/content/public/browser/permission_type.h
@@ -25,6 +25,7 @@
   BACKGROUND_SYNC = 10,
   FLASH = 11,
   SENSORS = 12,
+  ACCESSIBILITY_EVENTS = 13,
 
   // Always keep this at the end.
   NUM,
diff --git a/content/public/gpu/content_gpu_client.cc b/content/public/gpu/content_gpu_client.cc
index c2a8eacc..1f2226a 100644
--- a/content/public/gpu/content_gpu_client.cc
+++ b/content/public/gpu/content_gpu_client.cc
@@ -10,4 +10,12 @@
   return nullptr;
 }
 
+const gpu::GPUInfo* ContentGpuClient::GetGPUInfo() {
+  return nullptr;
+}
+
+const gpu::GpuFeatureInfo* ContentGpuClient::GetGpuFeatureInfo() {
+  return nullptr;
+}
+
 }  // namespace content
diff --git a/content/public/gpu/content_gpu_client.h b/content/public/gpu/content_gpu_client.h
index e9d2a97..cda3fd8 100644
--- a/content/public/gpu/content_gpu_client.h
+++ b/content/public/gpu/content_gpu_client.h
@@ -10,8 +10,10 @@
 #include "services/service_manager/public/cpp/binder_registry.h"
 
 namespace gpu {
-class SyncPointManager;
+struct GpuFeatureInfo;
+struct GPUInfo;
 struct GpuPreferences;
+class SyncPointManager;
 }
 
 namespace content {
@@ -21,13 +23,13 @@
  public:
   virtual ~ContentGpuClient() {}
 
-  // Initializes the client. |registry| will be passed to a ConnectionFilter
+  // Initializes the registry. |registry| will be passed to a ConnectionFilter
   // (which lives on the IO thread). Unlike other childthreads, the client must
   // register additional interfaces on this registry rather than just creating
   // more ConnectionFilters as the ConnectionFilter that wraps this registry
   // specifically does not bind any interface requests until after the Gpu
   // process receives CreateGpuService() from the browser.
-  virtual void Initialize(service_manager::BinderRegistry* registry) {}
+  virtual void InitializeRegistry(service_manager::BinderRegistry* registry) {}
 
   // Called during initialization once the GpuService has been initialized.
   virtual void GpuServiceInitialized(
@@ -36,6 +38,10 @@
   // Allows client to supply a SyncPointManager instance instead of having
   // content internally create one.
   virtual gpu::SyncPointManager* GetSyncPointManager();
+
+  // Allows client to re-use GPUInfo and GpuFeatureInfo if already computed.
+  virtual const gpu::GPUInfo* GetGPUInfo();
+  virtual const gpu::GpuFeatureInfo* GetGpuFeatureInfo();
 };
 
 }  // namespace content
diff --git a/content/public/renderer/pepper_plugin_instance.h b/content/public/renderer/pepper_plugin_instance.h
index 27465c86..dbad584 100644
--- a/content/public/renderer/pepper_plugin_instance.h
+++ b/content/public/renderer/pepper_plugin_instance.h
@@ -134,6 +134,13 @@
   // MoveRangeSelectionExtent.
   virtual void SetSelectionBounds(const gfx::PointF& base,
                                   const gfx::PointF& extent) = 0;
+
+  // Returns true if the plugin text can be edited.
+  virtual bool CanEditText() = 0;
+
+  // Replaces the plugin's selected text, if any, with |text|. Assumes
+  // CanEditText() returns true.
+  virtual void ReplaceSelection(const std::string& text) = 0;
 };
 
 }  // namespace content
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc
index b1fa9b28..55e6d48c0 100644
--- a/content/public/test/browser_test_utils.cc
+++ b/content/public/test/browser_test_utils.cc
@@ -1377,6 +1377,12 @@
       web_contents_impl->GetMainFrame()->GetRenderWidgetHost());
 }
 
+WebContents* GetFocusedWebContents(WebContents* web_contents) {
+  WebContentsImpl* web_contents_impl =
+      static_cast<WebContentsImpl*>(web_contents);
+  return web_contents_impl->GetFocusedWebContents();
+}
+
 void RouteMouseEvent(WebContents* web_contents, blink::WebMouseEvent* event) {
   WebContentsImpl* web_contents_impl =
       static_cast<WebContentsImpl*>(web_contents);
diff --git a/content/public/test/browser_test_utils.h b/content/public/test/browser_test_utils.h
index 4d7bde8..41e84d5 100644
--- a/content/public/test/browser_test_utils.h
+++ b/content/public/test/browser_test_utils.h
@@ -448,6 +448,9 @@
 // Returns the focused RenderWidgetHost.
 RenderWidgetHost* GetFocusedRenderWidgetHost(WebContents* web_contents);
 
+// Returns the focused WebContents.
+WebContents* GetFocusedWebContents(WebContents* web_contents);
+
 // Route the |event| through the RenderWidgetHostInputEventRouter. This allows
 // correct targeting of events to out of process iframes.
 void RouteMouseEvent(WebContents* web_contents, blink::WebMouseEvent* event);
diff --git a/content/public/test/test_download_request_handler.cc b/content/public/test/test_download_request_handler.cc
index c423e8ce..2ee6df20 100644
--- a/content/public/test/test_download_request_handler.cc
+++ b/content/public/test/test_download_request_handler.cc
@@ -406,6 +406,9 @@
                                            "Content-Length: %" PRId64 "\r\n",
                                            parameters_->size));
   response_info_.connection_info = parameters_->connection_type;
+  if (parameters_->support_byte_ranges)
+    response_info_.headers->AddHeader("Accept-Ranges: bytes");
+
   AddCommonEntityHeaders();
   NotifyHeadersCompleteAndPrepareToRead();
   return;
@@ -455,9 +458,6 @@
 }
 
 void TestDownloadRequestHandler::PartialResponseJob::AddCommonEntityHeaders() {
-  if (parameters_->support_byte_ranges)
-    response_info_.headers->AddHeader("Accept-Ranges: bytes");
-
   if (!parameters_->content_type.empty())
     response_info_.headers->AddHeader(base::StringPrintf(
         "Content-Type: %s", parameters_->content_type.c_str()));
diff --git a/content/public/test/test_download_request_handler.h b/content/public/test/test_download_request_handler.h
index 4025d34fb..440f876 100644
--- a/content/public/test/test_download_request_handler.h
+++ b/content/public/test/test_download_request_handler.h
@@ -144,7 +144,9 @@
     // response.
     int pattern_generator_seed;
 
-    // If true, the response contains a 'Accept-Ranges: bytes' header.
+    // Whether the server can handle partial request.
+    // If true, contains a 'Accept-Ranges: bytes' header for HTTP 200
+    // response, or contains 'Content-Range' header for HTTP 206 response.
     bool support_byte_ranges;
 
     // The connection type in the response.
diff --git a/content/renderer/media/webrtc/media_stream_video_webrtc_sink.cc b/content/renderer/media/webrtc/media_stream_video_webrtc_sink.cc
index 484c3bd..b924882e 100644
--- a/content/renderer/media/webrtc/media_stream_video_webrtc_sink.cc
+++ b/content/renderer/media/webrtc/media_stream_video_webrtc_sink.cc
@@ -268,7 +268,7 @@
 
   rtc::Optional<bool> needs_denoising =
       ToRtcOptional(video_track->noise_reduction());
-  bool is_screencast = is_screencast = video_track->is_screencast();
+  bool is_screencast = video_track->is_screencast();
   base::Optional<double> min_frame_rate = video_track->min_frame_rate();
   base::Optional<double> max_frame_rate = video_track->max_frame_rate();
 
diff --git a/content/renderer/pepper/fake_pepper_plugin_instance.cc b/content/renderer/pepper/fake_pepper_plugin_instance.cc
index c260bb7..28fbd56c 100644
--- a/content/renderer/pepper/fake_pepper_plugin_instance.cc
+++ b/content/renderer/pepper/fake_pepper_plugin_instance.cc
@@ -85,4 +85,10 @@
 void FakePepperPluginInstance::SetSelectionBounds(const gfx::PointF& base,
                                                   const gfx::PointF& extent) {}
 
+bool FakePepperPluginInstance::CanEditText() {
+  return false;
+}
+
+void FakePepperPluginInstance::ReplaceSelection(const std::string& text) {}
+
 }  // namespace content
diff --git a/content/renderer/pepper/fake_pepper_plugin_instance.h b/content/renderer/pepper/fake_pepper_plugin_instance.h
index ddac1d5d..b596e14f 100644
--- a/content/renderer/pepper/fake_pepper_plugin_instance.h
+++ b/content/renderer/pepper/fake_pepper_plugin_instance.h
@@ -47,6 +47,8 @@
   void MoveRangeSelectionExtent(const gfx::PointF& extent) override;
   void SetSelectionBounds(const gfx::PointF& base,
                           const gfx::PointF& extent) override;
+  bool CanEditText() override;
+  void ReplaceSelection(const std::string& text) override;
 
  private:
   GURL gurl_;
diff --git a/content/renderer/pepper/pepper_broker.cc b/content/renderer/pepper/pepper_broker.cc
index 0398960..e201224a 100644
--- a/content/renderer/pepper/pepper_broker.cc
+++ b/content/renderer/pepper/pepper_broker.cc
@@ -14,6 +14,10 @@
 #include "ppapi/proxy/ppapi_messages.h"
 #include "ppapi/shared_impl/platform_file.h"
 
+#if defined(OS_POSIX)
+#include "base/posix/eintr_wrapper.h"
+#endif
+
 #if defined(OS_WIN)
 #include <windows.h>
 #endif
@@ -38,7 +42,7 @@
 #elif defined(OS_POSIX)
   // If asked to close the source, we can simply re-use the source fd instead of
   // dup()ing and close()ing.
-  out_handle = ::dup(handle);
+  out_handle = HANDLE_EINTR(::dup(handle));
 #else
 #error Not implemented.
 #endif
diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.cc b/content/renderer/pepper/pepper_plugin_instance_impl.cc
index 843c8ae..b9c04dc0 100644
--- a/content/renderer/pepper/pepper_plugin_instance_impl.cc
+++ b/content/renderer/pepper/pepper_plugin_instance_impl.cc
@@ -1496,15 +1496,14 @@
 }
 
 bool PepperPluginInstanceImpl::CanEditText() {
-  return LoadPdfInterface()
-             ? PP_ToBool(plugin_pdf_interface_->CanEditText(pp_instance()))
-             : false;
+  if (!LoadPdfInterface())
+    return false;
+  return PP_ToBool(plugin_pdf_interface_->CanEditText(pp_instance()));
 }
 
 void PepperPluginInstanceImpl::ReplaceSelection(const std::string& text) {
   if (!LoadPdfInterface())
     return;
-
   plugin_pdf_interface_->ReplaceSelection(pp_instance(), text.c_str());
 }
 
diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.h b/content/renderer/pepper/pepper_plugin_instance_impl.h
index a5607b72..e2f29d92 100644
--- a/content/renderer/pepper/pepper_plugin_instance_impl.h
+++ b/content/renderer/pepper/pepper_plugin_instance_impl.h
@@ -420,8 +420,8 @@
   void MoveRangeSelectionExtent(const gfx::PointF& extent) override;
   void SetSelectionBounds(const gfx::PointF& base,
                           const gfx::PointF& extent) override;
-  bool CanEditText();
-  void ReplaceSelection(const std::string& text);
+  bool CanEditText() override;
+  void ReplaceSelection(const std::string& text) override;
 
   // PPB_Instance_API implementation.
   PP_Bool BindGraphics(PP_Instance instance, PP_Resource device) override;
diff --git a/content/renderer/service_worker/worker_fetch_context_impl.h b/content/renderer/service_worker/worker_fetch_context_impl.h
index c904e64..01b2e41 100644
--- a/content/renderer/service_worker/worker_fetch_context_impl.h
+++ b/content/renderer/service_worker/worker_fetch_context_impl.h
@@ -6,7 +6,7 @@
 #define CONTENT_RENDERER_SERVICE_WORKER_WORKER_FETCH_CONTEXT_IMPL_H_
 
 #include "content/child/child_url_loader_factory_getter.h"
-#include "content/common/service_worker/service_worker_provider_interfaces.mojom.h"
+#include "content/common/service_worker/service_worker_provider.mojom.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "content/public/common/service_worker_modes.h"
 #include "content/public/common/url_loader_factory.mojom.h"
diff --git a/content/shell/browser/layout_test/layout_test_message_filter.cc b/content/shell/browser/layout_test/layout_test_message_filter.cc
index 51e3d34a..5c8ba5b 100644
--- a/content/shell/browser/layout_test/layout_test_message_filter.cc
+++ b/content/shell/browser/layout_test/layout_test_message_filter.cc
@@ -182,6 +182,8 @@
     type = PermissionType::PROTECTED_MEDIA_IDENTIFIER;
   } else if (name == "background-sync") {
     type = PermissionType::BACKGROUND_SYNC;
+  } else if (name == "accessibility-events") {
+    type = PermissionType::ACCESSIBILITY_EVENTS;
   } else {
     NOTREACHED();
     type = PermissionType::NOTIFICATIONS;
diff --git a/content/shell/gpu/shell_content_gpu_client.cc b/content/shell/gpu/shell_content_gpu_client.cc
index ba58294..49484b36 100644
--- a/content/shell/gpu/shell_content_gpu_client.cc
+++ b/content/shell/gpu/shell_content_gpu_client.cc
@@ -15,7 +15,7 @@
 
 ShellContentGpuClient::~ShellContentGpuClient() = default;
 
-void ShellContentGpuClient::Initialize(
+void ShellContentGpuClient::InitializeRegistry(
     service_manager::BinderRegistry* registry) {
   registry->AddInterface<mojom::PowerMonitorTest>(
       base::Bind(&PowerMonitorTestImpl::MakeStrongBinding,
diff --git a/content/shell/gpu/shell_content_gpu_client.h b/content/shell/gpu/shell_content_gpu_client.h
index 70dfb12a..464706f8 100644
--- a/content/shell/gpu/shell_content_gpu_client.h
+++ b/content/shell/gpu/shell_content_gpu_client.h
@@ -19,7 +19,7 @@
   ~ShellContentGpuClient() override;
 
   // ContentGpuClient:
-  void Initialize(service_manager::BinderRegistry* registry) override;
+  void InitializeRegistry(service_manager::BinderRegistry* registry) override;
 
   DISALLOW_COPY_AND_ASSIGN(ShellContentGpuClient);
 };
diff --git a/content/test/data/allowed_frames.html b/content/test/data/allowed_frames.html
index cf088381..9b7b182 100644
--- a/content/test/data/allowed_frames.html
+++ b/content/test/data/allowed_frames.html
@@ -7,8 +7,8 @@
     replication. See https://crbug.com/705658 -->
   <iframe id="child-0"></iframe>
   <iframe id="child-1" allow></iframe>
-  <iframe id="child-2" allow="fullscreen vibrate" src="/cross-site/bar.com/title1.html"></iframe>
-  <iframe id="child-3" allow="fullscreen vibrate" src="title1.html"></iframe>
+  <iframe id="child-2" allow="fullscreen; vibrate" src="/cross-site/bar.com/title1.html"></iframe>
+  <iframe id="child-3" allow="fullscreen; vibrate" src="title1.html"></iframe>
 </body>
 </html>
 
diff --git a/content/test/data/feature-policy-main.html.mock-http-headers b/content/test/data/feature-policy-main.html.mock-http-headers
index a75ac49..27f74bf 100644
--- a/content/test/data/feature-policy-main.html.mock-http-headers
+++ b/content/test/data/feature-policy-main.html.mock-http-headers
@@ -1,2 +1,2 @@
 HTTP/1.1 200 OK
-Feature-Policy: {"vibrate":["self", "http://example.com/"]}
+Feature-Policy: vibrate 'self' http://example.com/
diff --git a/content/test/data/feature-policy1.html.mock-http-headers b/content/test/data/feature-policy1.html.mock-http-headers
index 21c4d0c..7cb56a96 100644
--- a/content/test/data/feature-policy1.html.mock-http-headers
+++ b/content/test/data/feature-policy1.html.mock-http-headers
@@ -1,2 +1,2 @@
 HTTP/1.1 200 OK
-Feature-Policy: {"vibrate":["self"]}
+Feature-Policy: vibrate 'self'
diff --git a/content/test/data/feature-policy2.html.mock-http-headers b/content/test/data/feature-policy2.html.mock-http-headers
index e42864b1..d3732f5 100644
--- a/content/test/data/feature-policy2.html.mock-http-headers
+++ b/content/test/data/feature-policy2.html.mock-http-headers
@@ -1,2 +1,2 @@
 HTTP/1.1 200 OK
-Feature-Policy: {"vibrate":["*"]}
+Feature-Policy: vibrate *
diff --git a/content/utility/utility_service_factory.cc b/content/utility/utility_service_factory.cc
index bf9cf798..f205d99 100644
--- a/content/utility/utility_service_factory.cc
+++ b/content/utility/utility_service_factory.cc
@@ -25,12 +25,17 @@
 
 #if BUILDFLAG(ENABLE_LIBRARY_CDMS)
 #include "base/memory/ptr_util.h"
+#include "media/base/scoped_callback_runner.h"
 #include "media/cdm/cdm_adapter_factory.h"           // nogncheck
+#include "media/cdm/cdm_helpers.h"                   // nogncheck
 #include "media/mojo/features.h"                     // nogncheck
 #include "media/mojo/interfaces/constants.mojom.h"   // nogncheck
+#include "media/mojo/interfaces/output_protection.mojom.h"      // nogncheck
+#include "media/mojo/interfaces/platform_verification.mojom.h"  // nogncheck
 #include "media/mojo/services/media_service.h"       // nogncheck
 #include "media/mojo/services/mojo_cdm_allocator.h"  // nogncheck
 #include "media/mojo/services/mojo_media_client.h"   // nogncheck
+#include "services/service_manager/public/cpp/connect.h"
 #endif
 
 namespace {
@@ -50,8 +55,112 @@
 static_assert(BUILDFLAG(ENABLE_STANDALONE_CDM_SERVICE), "");
 static_assert(BUILDFLAG(ENABLE_MOJO_CDM), "");
 
-std::unique_ptr<media::CdmAllocator> CreateCdmAllocator() {
-  return base::MakeUnique<media::MojoCdmAllocator>();
+// Helper class that connects the CDM to various auxiliary services. All
+// additional services (FileIO, memory allocation, output protection, and
+// platform verification) are lazily created.
+class MojoCdmHelper : public media::CdmAuxiliaryHelper {
+ public:
+  explicit MojoCdmHelper(
+      service_manager::mojom::InterfaceProvider* interface_provider)
+      : interface_provider_(interface_provider) {}
+  ~MojoCdmHelper() override = default;
+
+  // CdmAuxiliaryHelper implementation.
+  std::unique_ptr<media::CdmFileIO> CreateCdmFileIO(
+      cdm::FileIOClient* client) override {
+    // TODO(jrummell): Hook up File IO. http://crbug.com/479923.
+    return nullptr;
+  }
+
+  cdm::Buffer* CreateCdmBuffer(size_t capacity) override {
+    return GetAllocator()->CreateCdmBuffer(capacity);
+  }
+
+  std::unique_ptr<media::VideoFrameImpl> CreateCdmVideoFrame() override {
+    return GetAllocator()->CreateCdmVideoFrame();
+  }
+
+  void QueryStatus(QueryStatusCB callback) override {
+    QueryStatusCB scoped_callback =
+        media::ScopedCallbackRunner(std::move(callback), false, 0, 0);
+    if (!ConnectToOutputProtection())
+      return;
+
+    output_protection_->QueryStatus(std::move(scoped_callback));
+  }
+
+  void EnableProtection(uint32_t desired_protection_mask,
+                        EnableProtectionCB callback) override {
+    EnableProtectionCB scoped_callback =
+        media::ScopedCallbackRunner(std::move(callback), false);
+    if (!ConnectToOutputProtection())
+      return;
+
+    output_protection_->EnableProtection(desired_protection_mask,
+                                         std::move(scoped_callback));
+  }
+
+  void ChallengePlatform(const std::string& service_id,
+                         const std::string& challenge,
+                         ChallengePlatformCB callback) override {
+    ChallengePlatformCB scoped_callback =
+        media::ScopedCallbackRunner(std::move(callback), false, "", "", "");
+    if (!ConnectToPlatformVerification())
+      return;
+
+    platform_verification_->ChallengePlatform(service_id, challenge,
+                                              std::move(scoped_callback));
+  }
+
+  void GetStorageId(StorageIdCB callback) override {
+    StorageIdCB scoped_callback = media::ScopedCallbackRunner(
+        std::move(callback), std::vector<uint8_t>());
+    // TODO(jrummell): Hook up GetStorageId() once added to the mojo interface.
+    // http://crbug.com/478960.
+  }
+
+ private:
+  // All services are created lazily.
+  media::CdmAllocator* GetAllocator() {
+    if (!allocator_)
+      allocator_ = base::MakeUnique<media::MojoCdmAllocator>();
+    return allocator_.get();
+  }
+
+  bool ConnectToOutputProtection() {
+    if (!output_protection_attempted_) {
+      output_protection_attempted_ = true;
+      service_manager::GetInterface<media::mojom::OutputProtection>(
+          interface_provider_, &output_protection_);
+    }
+    return output_protection_.is_bound();
+  }
+
+  bool ConnectToPlatformVerification() {
+    if (!platform_verification_attempted_) {
+      platform_verification_attempted_ = true;
+      service_manager::GetInterface<media::mojom::PlatformVerification>(
+          interface_provider_, &platform_verification_);
+    }
+    return platform_verification_.is_bound();
+  }
+
+  // Provides interfaces when needed.
+  service_manager::mojom::InterfaceProvider* interface_provider_;
+
+  // Keep track if connection to the Mojo service has been attempted once.
+  // The service may not exist, or may fail later.
+  bool output_protection_attempted_ = false;
+  bool platform_verification_attempted_ = false;
+
+  std::unique_ptr<media::CdmAllocator> allocator_;
+  media::mojom::OutputProtectionPtr output_protection_;
+  media::mojom::PlatformVerificationPtr platform_verification_;
+};
+
+std::unique_ptr<media::CdmAuxiliaryHelper> CreateCdmHelper(
+    service_manager::mojom::InterfaceProvider* interface_provider) {
+  return base::MakeUnique<MojoCdmHelper>(interface_provider);
 }
 
 class CdmMojoMediaClient final : public media::MojoMediaClient {
@@ -62,7 +171,7 @@
   std::unique_ptr<media::CdmFactory> CreateCdmFactory(
       service_manager::mojom::InterfaceProvider* host_interfaces) override {
     return base::MakeUnique<media::CdmAdapterFactory>(
-        base::Bind(&CreateCdmAllocator));
+        base::Bind(&CreateCdmHelper, host_interfaces));
   }
 };
 
diff --git a/device/bluetooth/adapter.cc b/device/bluetooth/adapter.cc
index fb1f9998..bd8883d 100644
--- a/device/bluetooth/adapter.cc
+++ b/device/bluetooth/adapter.cc
@@ -149,7 +149,7 @@
     std::unique_ptr<device::BluetoothDiscoverySession> session) {
   mojom::DiscoverySessionPtr session_ptr;
   mojo::MakeStrongBinding(
-      base::MakeUnique<DiscoverySession>(std::move(session)),
+      std::make_unique<DiscoverySession>(std::move(session)),
       mojo::MakeRequest(&session_ptr));
   std::move(callback).Run(std::move(session_ptr));
 }
diff --git a/device/bluetooth/adapter_factory.cc b/device/bluetooth/adapter_factory.cc
index f334779..8153650 100644
--- a/device/bluetooth/adapter_factory.cc
+++ b/device/bluetooth/adapter_factory.cc
@@ -17,7 +17,7 @@
 
 // static
 void AdapterFactory::Create(mojom::AdapterFactoryRequest request) {
-  mojo::MakeStrongBinding(base::MakeUnique<AdapterFactory>(),
+  mojo::MakeStrongBinding(std::make_unique<AdapterFactory>(),
                           std::move(request));
 }
 
@@ -35,7 +35,7 @@
     GetAdapterCallback callback,
     scoped_refptr<device::BluetoothAdapter> adapter) {
   mojom::AdapterPtr adapter_ptr;
-  mojo::MakeStrongBinding(base::MakeUnique<Adapter>(adapter),
+  mojo::MakeStrongBinding(std::make_unique<Adapter>(adapter),
                           mojo::MakeRequest(&adapter_ptr));
   std::move(callback).Run(std::move(adapter_ptr));
 }
diff --git a/device/bluetooth/bluetooth_adapter_factory.cc b/device/bluetooth/bluetooth_adapter_factory.cc
index f1e62dc..bde11f01 100644
--- a/device/bluetooth/bluetooth_adapter_factory.cc
+++ b/device/bluetooth/bluetooth_adapter_factory.cc
@@ -163,7 +163,7 @@
 
 std::unique_ptr<BluetoothAdapterFactory::GlobalValuesForTesting>
 BluetoothAdapterFactory::InitGlobalValuesForTesting() {
-  auto v = base::MakeUnique<BluetoothAdapterFactory::GlobalValuesForTesting>();
+  auto v = std::make_unique<BluetoothAdapterFactory::GlobalValuesForTesting>();
   values_for_testing_ = v->GetWeakPtr();
   return v;
 }
diff --git a/device/bluetooth/bluetooth_adapter_win_unittest.cc b/device/bluetooth/bluetooth_adapter_win_unittest.cc
index fa481ff..0537efb 100644
--- a/device/bluetooth/bluetooth_adapter_win_unittest.cc
+++ b/device/bluetooth/bluetooth_adapter_win_unittest.cc
@@ -438,9 +438,9 @@
 
 TEST_F(BluetoothAdapterWinTest, DevicesPolled) {
   std::vector<std::unique_ptr<BluetoothTaskManagerWin::DeviceState>> devices;
-  devices.push_back(base::MakeUnique<BluetoothTaskManagerWin::DeviceState>());
-  devices.push_back(base::MakeUnique<BluetoothTaskManagerWin::DeviceState>());
-  devices.push_back(base::MakeUnique<BluetoothTaskManagerWin::DeviceState>());
+  devices.push_back(std::make_unique<BluetoothTaskManagerWin::DeviceState>());
+  devices.push_back(std::make_unique<BluetoothTaskManagerWin::DeviceState>());
+  devices.push_back(std::make_unique<BluetoothTaskManagerWin::DeviceState>());
 
   BluetoothTaskManagerWin::DeviceState* android_phone_state = devices[0].get();
   BluetoothTaskManagerWin::DeviceState* laptop_state = devices[1].get();
@@ -482,7 +482,7 @@
 
   // Add a service
   laptop_state->service_record_states.push_back(
-      base::MakeUnique<BluetoothTaskManagerWin::ServiceRecordState>());
+      std::make_unique<BluetoothTaskManagerWin::ServiceRecordState>());
   BluetoothTaskManagerWin::ServiceRecordState* audio_state =
       laptop_state->service_record_states.back().get();
   audio_state->name = kTestAudioSdpName;
diff --git a/device/bluetooth/bluetooth_advertisement_unittest.cc b/device/bluetooth/bluetooth_advertisement_unittest.cc
index a0ef62c..83287daf 100644
--- a/device/bluetooth/bluetooth_advertisement_unittest.cc
+++ b/device/bluetooth/bluetooth_advertisement_unittest.cc
@@ -34,7 +34,7 @@
   ASSERT_FALSE(data.service_uuids().get());
   // Assign Service UUID.
   data.set_service_uuids(
-      base::MakeUnique<BluetoothAdvertisement::UUIDList>(uuids));
+      std::make_unique<BluetoothAdvertisement::UUIDList>(uuids));
   // Retrieve Service UUID.
   ASSERT_EQ(*data.service_uuids(), uuids);
   // Retrieve again.
@@ -44,7 +44,7 @@
   ASSERT_FALSE(data.manufacturer_data().get());
   // Assign Manufacturer Data.
   data.set_manufacturer_data(
-      base::MakeUnique<BluetoothAdvertisement::ManufacturerData>(
+      std::make_unique<BluetoothAdvertisement::ManufacturerData>(
           manufacturer_data));
   // Retrieve Manufacturer Data.
   ASSERT_EQ(*data.manufacturer_data(), manufacturer_data);
@@ -55,7 +55,7 @@
   ASSERT_FALSE(data.solicit_uuids().get());
   // Assign Solicit UUIDs.
   data.set_solicit_uuids(
-      base::MakeUnique<BluetoothAdvertisement::UUIDList>(uuids));
+      std::make_unique<BluetoothAdvertisement::UUIDList>(uuids));
   // Retrieve Solicit UUIDs.
   ASSERT_EQ(*data.solicit_uuids(), uuids);
   // Retieve again.
@@ -65,7 +65,7 @@
   ASSERT_FALSE(data.service_data().get());
   // Assign Service Data.
   data.set_service_data(
-      base::MakeUnique<BluetoothAdvertisement::ServiceData>(service_data));
+      std::make_unique<BluetoothAdvertisement::ServiceData>(service_data));
   // Retrieve Service Data.
   ASSERT_EQ(*data.service_data(), service_data);
   // Retrieve again.
diff --git a/device/bluetooth/bluetooth_device.cc b/device/bluetooth/bluetooth_device.cc
index 49cf01b0..02374c9f 100644
--- a/device/bluetooth/bluetooth_device.cc
+++ b/device/bluetooth/bluetooth_device.cc
@@ -467,7 +467,7 @@
 void BluetoothDevice::DidConnectGatt() {
   for (const auto& callback : create_gatt_connection_success_callbacks_) {
     callback.Run(
-        base::MakeUnique<BluetoothGattConnection>(adapter_, GetAddress()));
+        std::make_unique<BluetoothGattConnection>(adapter_, GetAddress()));
   }
   create_gatt_connection_success_callbacks_.clear();
   create_gatt_connection_error_callbacks_.clear();
diff --git a/device/bluetooth/bluetooth_device_win.cc b/device/bluetooth/bluetooth_device_win.cc
index 88bd521b..35ceee7 100644
--- a/device/bluetooth/bluetooth_device_win.cc
+++ b/device/bluetooth/bluetooth_device_win.cc
@@ -243,7 +243,7 @@
       new_service_records;
   for (auto iter = device_state.service_record_states.begin();
        iter != device_state.service_record_states.end(); ++iter) {
-    auto service_record = base::MakeUnique<BluetoothServiceRecordWin>(
+    auto service_record = std::make_unique<BluetoothServiceRecordWin>(
         address_, (*iter)->name, (*iter)->sdp_bytes, (*iter)->gatt_uuid);
     new_services.insert(service_record->uuid());
     new_service_records[service_record->uuid().canonical_value()] =
@@ -299,7 +299,7 @@
   service_record_list_.clear();
 
   for (const auto& record_state : device_state.service_record_states) {
-    auto service_record = base::MakeUnique<BluetoothServiceRecordWin>(
+    auto service_record = std::make_unique<BluetoothServiceRecordWin>(
         device_state.address, record_state->name, record_state->sdp_bytes,
         record_state->gatt_uuid);
     uuids_.insert(service_record->uuid());
diff --git a/device/bluetooth/bluetooth_device_win_unittest.cc b/device/bluetooth/bluetooth_device_win_unittest.cc
index b75d538..daefa6b 100644
--- a/device/bluetooth/bluetooth_device_win_unittest.cc
+++ b/device/bluetooth/bluetooth_device_win_unittest.cc
@@ -55,13 +55,13 @@
     device_state_->address = kDeviceAddress;
 
     auto audio_state =
-        base::MakeUnique<BluetoothTaskManagerWin::ServiceRecordState>();
+        std::make_unique<BluetoothTaskManagerWin::ServiceRecordState>();
     audio_state->name = kTestAudioSdpName;
     base::HexStringToBytes(kTestAudioSdpBytes, &audio_state->sdp_bytes);
     device_state_->service_record_states.push_back(std::move(audio_state));
 
     auto video_state =
-        base::MakeUnique<BluetoothTaskManagerWin::ServiceRecordState>();
+        std::make_unique<BluetoothTaskManagerWin::ServiceRecordState>();
     video_state->name = kTestVideoSdpName;
     base::HexStringToBytes(kTestVideoSdpBytes, &video_state->sdp_bytes);
     device_state_->service_record_states.push_back(std::move(video_state));
diff --git a/device/bluetooth/bluetooth_discovery_filter.cc b/device/bluetooth/bluetooth_discovery_filter.cc
index 8fe0eb7..1660912 100644
--- a/device/bluetooth/bluetooth_discovery_filter.cc
+++ b/device/bluetooth/bluetooth_discovery_filter.cc
@@ -76,7 +76,7 @@
       return;
   }
 
-  uuids_.push_back(base::MakeUnique<device::BluetoothUUID>(uuid));
+  uuids_.push_back(std::make_unique<device::BluetoothUUID>(uuid));
 }
 
 void BluetoothDiscoveryFilter::CopyFrom(
diff --git a/device/bluetooth/bluetooth_low_energy_win.cc b/device/bluetooth/bluetooth_low_energy_win.cc
index 53c5a39..e07326ab 100644
--- a/device/bluetooth/bluetooth_low_energy_win.cc
+++ b/device/bluetooth/bluetooth_low_energy_win.cc
@@ -408,7 +408,7 @@
 
   for (USHORT i = 0; i < actual_length; ++i) {
     BTH_LE_GATT_SERVICE& gatt_service(gatt_services.get()[i]);
-    auto service_info = base::MakeUnique<BluetoothLowEnergyServiceInfo>();
+    auto service_info = std::make_unique<BluetoothLowEnergyServiceInfo>();
     service_info->uuid = gatt_service.ServiceUuid;
     service_info->attribute_handle = gatt_service.AttributeHandle;
     services->push_back(std::move(service_info));
diff --git a/device/bluetooth/bluetooth_low_energy_win_fake.cc b/device/bluetooth/bluetooth_low_energy_win_fake.cc
index bfbc1b2..553cbb2a 100644
--- a/device/bluetooth/bluetooth_low_energy_win_fake.cc
+++ b/device/bluetooth/bluetooth_low_energy_win_fake.cc
@@ -52,7 +52,7 @@
   for (auto& device : simulated_devices_) {
     if (device.second->marked_as_deleted)
       continue;
-    auto device_info = base::MakeUnique<BluetoothLowEnergyDeviceInfo>();
+    auto device_info = std::make_unique<BluetoothLowEnergyDeviceInfo>();
     *device_info = *(device.second->device_info);
     devices->push_back(std::move(device_info));
   }
@@ -70,7 +70,7 @@
 
   for (auto& device : simulated_devices_) {
     for (auto& service : device.second->primary_services) {
-      auto device_info = base::MakeUnique<BluetoothLowEnergyDeviceInfo>();
+      auto device_info = std::make_unique<BluetoothLowEnergyDeviceInfo>();
       *device_info = *(device.second->device_info);
       base::string16 path = GenerateGattServiceDevicePath(
           device.second->device_info->path.value(),
@@ -105,7 +105,7 @@
   if (service_attribute_handles.empty()) {
     // Return all primary services for BLE device.
     for (auto& primary_service : it_d->second->primary_services) {
-      auto service_info = base::MakeUnique<BluetoothLowEnergyServiceInfo>();
+      auto service_info = std::make_unique<BluetoothLowEnergyServiceInfo>();
       service_info->uuid = primary_service.second->service_info->ServiceUuid;
       service_info->attribute_handle =
           primary_service.second->service_info->AttributeHandle;
@@ -115,7 +115,7 @@
     // Return corresponding GATT service for BLE GATT service device.
     GattService* target_service =
         GetSimulatedGattService(it_d->second.get(), service_attribute_handles);
-    auto service_info = base::MakeUnique<BluetoothLowEnergyServiceInfo>();
+    auto service_info = std::make_unique<BluetoothLowEnergyServiceInfo>();
     service_info->uuid = target_service->service_info->ServiceUuid;
     service_info->attribute_handle =
         target_service->service_info->AttributeHandle;
diff --git a/device/bluetooth/bluetooth_task_manager_win.cc b/device/bluetooth/bluetooth_task_manager_win.cc
index 4c6c0e2..55716ff 100644
--- a/device/bluetooth/bluetooth_task_manager_win.cc
+++ b/device/bluetooth/bluetooth_task_manager_win.cc
@@ -529,7 +529,7 @@
   }
 
   while (true) {
-    auto device_state = base::MakeUnique<DeviceState>();
+    auto device_state = std::make_unique<DeviceState>();
     GetDeviceState(device_info, device_state.get());
     device_list->push_back(std::move(device_state));
 
@@ -574,7 +574,7 @@
   }
 
   for (const auto& device_info : btle_devices) {
-    auto device_state = base::MakeUnique<DeviceState>();
+    auto device_state = std::make_unique<DeviceState>();
     device_state->name = device_info->friendly_name;
     device_state->address =
         BluetoothAddressToCanonicalString(device_info->address);
@@ -694,7 +694,7 @@
       WSALookupServiceEnd(sdp_handle);
       return last_error;
     }
-    auto service_record_state = base::MakeUnique<ServiceRecordState>();
+    auto service_record_state = std::make_unique<ServiceRecordState>();
     service_record_state->name =
         base::SysWideToUTF8(sdp_result_data->lpszServiceInstanceName);
     for (uint64_t i = 0; i < sdp_result_data->lpBlob->cbSize; i++) {
@@ -731,7 +731,7 @@
   }
 
   for (const auto& service : services) {
-    auto service_state = base::MakeUnique<ServiceRecordState>();
+    auto service_state = std::make_unique<ServiceRecordState>();
     service_state->gatt_uuid =
         BluetoothLowEnergyUuidToBluetoothUuid(service->uuid);
     service_state->attribute_handle = service->attribute_handle;
diff --git a/device/bluetooth/bluez/bluetooth_advertisement_bluez_unittest.cc b/device/bluetooth/bluez/bluetooth_advertisement_bluez_unittest.cc
index c766f3c..81518ba 100644
--- a/device/bluetooth/bluez/bluetooth_advertisement_bluez_unittest.cc
+++ b/device/bluetooth/bluez/bluetooth_advertisement_bluez_unittest.cc
@@ -99,16 +99,16 @@
 
   std::unique_ptr<BluetoothAdvertisement::Data> CreateAdvertisementData() {
     std::unique_ptr<BluetoothAdvertisement::Data> data =
-        base::MakeUnique<BluetoothAdvertisement::Data>(
+        std::make_unique<BluetoothAdvertisement::Data>(
             BluetoothAdvertisement::ADVERTISEMENT_TYPE_BROADCAST);
     data->set_service_uuids(
-        base::MakeUnique<BluetoothAdvertisement::UUIDList>());
+        std::make_unique<BluetoothAdvertisement::UUIDList>());
     data->set_manufacturer_data(
-        base::MakeUnique<BluetoothAdvertisement::ManufacturerData>());
+        std::make_unique<BluetoothAdvertisement::ManufacturerData>());
     data->set_solicit_uuids(
-        base::MakeUnique<BluetoothAdvertisement::UUIDList>());
+        std::make_unique<BluetoothAdvertisement::UUIDList>());
     data->set_service_data(
-        base::MakeUnique<BluetoothAdvertisement::ServiceData>());
+        std::make_unique<BluetoothAdvertisement::ServiceData>());
     return data;
   }
 
diff --git a/device/bluetooth/bluez/bluetooth_service_attribute_value_bluez.cc b/device/bluetooth/bluez/bluetooth_service_attribute_value_bluez.cc
index 2c484c1d..2a14518 100644
--- a/device/bluetooth/bluez/bluetooth_service_attribute_value_bluez.cc
+++ b/device/bluetooth/bluez/bluetooth_service_attribute_value_bluez.cc
@@ -12,7 +12,7 @@
 namespace bluez {
 
 BluetoothServiceAttributeValueBlueZ::BluetoothServiceAttributeValueBlueZ()
-    : type_(NULLTYPE), size_(0), value_(base::MakeUnique<base::Value>()) {}
+    : type_(NULLTYPE), size_(0), value_(std::make_unique<base::Value>()) {}
 
 BluetoothServiceAttributeValueBlueZ::BluetoothServiceAttributeValueBlueZ(
     Type type,
@@ -40,7 +40,7 @@
     size_ = attribute.size_;
     if (attribute.type_ == SEQUENCE) {
       value_ = nullptr;
-      sequence_ = base::MakeUnique<Sequence>(*attribute.sequence_);
+      sequence_ = std::make_unique<Sequence>(*attribute.sequence_);
     } else {
       value_ = attribute.value_->CreateDeepCopy();
       sequence_ = nullptr;
diff --git a/device/bluetooth/bluez/bluetooth_service_attribute_value_bluez_unittest.cc b/device/bluetooth/bluez/bluetooth_service_attribute_value_bluez_unittest.cc
index ba66a4b2..377c163 100644
--- a/device/bluetooth/bluez/bluetooth_service_attribute_value_bluez_unittest.cc
+++ b/device/bluetooth/bluez/bluetooth_service_attribute_value_bluez_unittest.cc
@@ -41,14 +41,14 @@
 // in the call. This function helps us avoid all that ugly syntax.
 std::unique_ptr<Sequence> MakeSequence(
     const std::initializer_list<BluetoothServiceAttributeValueBlueZ> list) {
-  return base::MakeUnique<Sequence>(list);
+  return std::make_unique<Sequence>(list);
 }
 
 }  // namespace
 
 TEST(BluetoothServiceAttributeBlueZTest, BasicValue) {
   BluetoothServiceAttributeValueBlueZ value1(
-      Type::UUID, 16, base::MakeUnique<base::Value>(kServiceUuid));
+      Type::UUID, 16, std::make_unique<base::Value>(kServiceUuid));
   BluetoothServiceAttributeValueBlueZ value2 = value1;
 
   CheckUuidValue(value2, kServiceUuid);
@@ -56,11 +56,11 @@
 
 TEST(BluetoothServiceAttributeBlueZTest, Sequence) {
   BluetoothServiceAttributeValueBlueZ value1(
-      Type::UUID, 16, base::MakeUnique<base::Value>(kServiceUuid));
+      Type::UUID, 16, std::make_unique<base::Value>(kServiceUuid));
   BluetoothServiceAttributeValueBlueZ value2(
-      Type::INT, 4, base::MakeUnique<base::Value>(0x1337));
+      Type::INT, 4, std::make_unique<base::Value>(0x1337));
   BluetoothServiceAttributeValueBlueZ value3(
-      Type::INT, 4, base::MakeUnique<base::Value>(0x7331));
+      Type::INT, 4, std::make_unique<base::Value>(0x7331));
 
   BluetoothServiceAttributeValueBlueZ* value4 =
       new BluetoothServiceAttributeValueBlueZ(
@@ -80,9 +80,9 @@
 
 TEST(BluetoothServiceAttributeBlueZTest, NestedValue) {
   BluetoothServiceAttributeValueBlueZ value1(
-      Type::UUID, 16, base::MakeUnique<base::Value>(kServiceUuid));
+      Type::UUID, 16, std::make_unique<base::Value>(kServiceUuid));
   BluetoothServiceAttributeValueBlueZ value2(
-      Type::INT, 4, base::MakeUnique<base::Value>(0x1337));
+      Type::INT, 4, std::make_unique<base::Value>(0x1337));
   BluetoothServiceAttributeValueBlueZ value3(MakeSequence({value1, value2}));
   BluetoothServiceAttributeValueBlueZ value4(MakeSequence({value3}));
 
@@ -124,11 +124,11 @@
 
 TEST(BluetoothServiceAttributeBlueZTest, CopyAssignment) {
   BluetoothServiceAttributeValueBlueZ value1(
-      Type::UUID, 16, base::MakeUnique<base::Value>(kServiceUuid));
+      Type::UUID, 16, std::make_unique<base::Value>(kServiceUuid));
   BluetoothServiceAttributeValueBlueZ value2(
-      Type::INT, 4, base::MakeUnique<base::Value>(0x1337));
+      Type::INT, 4, std::make_unique<base::Value>(0x1337));
   BluetoothServiceAttributeValueBlueZ value3(
-      Type::INT, 4, base::MakeUnique<base::Value>(0x7331));
+      Type::INT, 4, std::make_unique<base::Value>(0x7331));
   std::unique_ptr<BluetoothServiceAttributeValueBlueZ> value4(
       new BluetoothServiceAttributeValueBlueZ(
           MakeSequence({value1, value2, value3})));
diff --git a/device/bluetooth/bluez/bluetooth_service_record_bluez_unittest.cc b/device/bluetooth/bluez/bluetooth_service_record_bluez_unittest.cc
index 0c2433ce0..af35997 100644
--- a/device/bluetooth/bluez/bluetooth_service_record_bluez_unittest.cc
+++ b/device/bluetooth/bluez/bluetooth_service_record_bluez_unittest.cc
@@ -130,7 +130,7 @@
     record.AddRecordEntry(kServiceUuidAttributeId,
                           BluetoothServiceAttributeValueBlueZ(
                               BluetoothServiceAttributeValueBlueZ::UUID, 16,
-                              base::MakeUnique<base::Value>(uuid)));
+                              std::make_unique<base::Value>(uuid)));
     return record;
   }
 
diff --git a/device/bluetooth/dbus/bluetooth_device_client.cc b/device/bluetooth/dbus/bluetooth_device_client.cc
index c79cba4..38a4c46 100644
--- a/device/bluetooth/dbus/bluetooth_device_client.cc
+++ b/device/bluetooth/dbus/bluetooth_device_client.cc
@@ -54,19 +54,19 @@
           uint8_t byte;
           if (!struct_reader->PopVariantOfByte(&byte))
             return nullptr;
-          value = base::MakeUnique<base::Value>(byte);
+          value = std::make_unique<base::Value>(byte);
           break;
         case 2:
           uint16_t short_val;
           if (!struct_reader->PopVariantOfUint16(&short_val))
             return nullptr;
-          value = base::MakeUnique<base::Value>(short_val);
+          value = std::make_unique<base::Value>(short_val);
           break;
         case 4:
           uint32_t val;
           if (!struct_reader->PopVariantOfUint32(&val))
             return nullptr;
-          value = base::MakeUnique<base::Value>(static_cast<int32_t>(val));
+          value = std::make_unique<base::Value>(static_cast<int32_t>(val));
           break;
         case 8:
         // Fall through.
@@ -87,14 +87,14 @@
       std::string str;
       if (!struct_reader->PopVariantOfString(&str))
         return nullptr;
-      value = base::MakeUnique<base::Value>(str);
+      value = std::make_unique<base::Value>(str);
       break;
     }
     case bluez::BluetoothServiceAttributeValueBlueZ::BOOL: {
       bool b;
       if (!struct_reader->PopVariantOfBool(&b))
         return nullptr;
-      value = base::MakeUnique<base::Value>(b);
+      value = std::make_unique<base::Value>(b);
       break;
     }
     case bluez::BluetoothServiceAttributeValueBlueZ::SEQUENCE: {
@@ -105,7 +105,7 @@
       if (!variant_reader.PopArray(&array_reader))
         return nullptr;
       std::unique_ptr<BluetoothServiceAttributeValueBlueZ::Sequence> sequence =
-          base::MakeUnique<BluetoothServiceAttributeValueBlueZ::Sequence>();
+          std::make_unique<BluetoothServiceAttributeValueBlueZ::Sequence>();
       while (array_reader.HasMoreData()) {
         dbus::MessageReader sequence_element_struct_reader(nullptr);
         if (!array_reader.PopStruct(&sequence_element_struct_reader))
@@ -116,18 +116,18 @@
           return nullptr;
         sequence->emplace_back(*attribute_value);
       }
-      return base::MakeUnique<BluetoothServiceAttributeValueBlueZ>(
+      return std::make_unique<BluetoothServiceAttributeValueBlueZ>(
           std::move(sequence));
     }
   }
-  return base::MakeUnique<BluetoothServiceAttributeValueBlueZ>(
+  return std::make_unique<BluetoothServiceAttributeValueBlueZ>(
       type, size, std::move(value));
 }
 
 std::unique_ptr<BluetoothServiceRecordBlueZ> ReadRecord(
     dbus::MessageReader* array_reader) {
   std::unique_ptr<BluetoothServiceRecordBlueZ> record =
-      base::MakeUnique<BluetoothServiceRecordBlueZ>();
+      std::make_unique<BluetoothServiceRecordBlueZ>();
   while (array_reader->HasMoreData()) {
     dbus::MessageReader dict_entry_reader(nullptr);
     if (!array_reader->PopDictEntry(&dict_entry_reader))
diff --git a/device/bluetooth/dbus/bluetooth_gatt_application_service_provider.cc b/device/bluetooth/dbus/bluetooth_gatt_application_service_provider.cc
index 5d436b8..92f1100 100644
--- a/device/bluetooth/dbus/bluetooth_gatt_application_service_provider.cc
+++ b/device/bluetooth/dbus/bluetooth_gatt_application_service_provider.cc
@@ -116,7 +116,7 @@
       characteristic_providers_.push_back(
           base::WrapUnique(BluetoothGattCharacteristicServiceProvider::Create(
               bus, characteristic.second->object_path(),
-              base::MakeUnique<BluetoothGattCharacteristicDelegateWrapper>(
+              std::make_unique<BluetoothGattCharacteristicDelegateWrapper>(
                   service.second, characteristic.second.get()),
               characteristic.second->GetUUID().value(),
               FlagsFromProperties(characteristic.second->GetProperties()),
@@ -125,7 +125,7 @@
         descriptor_providers_.push_back(
             base::WrapUnique(BluetoothGattDescriptorServiceProvider::Create(
                 bus, descriptor->object_path(),
-                base::MakeUnique<BluetoothGattDescriptorDelegateWrapper>(
+                std::make_unique<BluetoothGattDescriptorDelegateWrapper>(
                     service.second, descriptor.get()),
                 descriptor->GetUUID().value(),
                 FlagsFromPermissions(descriptor->GetPermissions()),
@@ -161,7 +161,7 @@
     return base::WrapUnique(new BluetoothGattApplicationServiceProviderImpl(
         bus, object_path, services));
   }
-  return base::MakeUnique<FakeBluetoothGattApplicationServiceProvider>(
+  return std::make_unique<FakeBluetoothGattApplicationServiceProvider>(
       object_path, services);
 }
 
diff --git a/device/bluetooth/dbus/bluetooth_gatt_application_service_provider_unittest.cc b/device/bluetooth/dbus/bluetooth_gatt_application_service_provider_unittest.cc
index da236c3f..35725ba 100644
--- a/device/bluetooth/dbus/bluetooth_gatt_application_service_provider_unittest.cc
+++ b/device/bluetooth/dbus/bluetooth_gatt_application_service_provider_unittest.cc
@@ -293,7 +293,7 @@
     const std::string& full_service_path =
         std::string(kAppObjectPath) + "/" + service_path;
     app_provider->service_providers_.push_back(
-        base::MakeUnique<BluetoothGattServiceServiceProviderImpl>(
+        std::make_unique<BluetoothGattServiceServiceProviderImpl>(
             nullptr, dbus::ObjectPath(full_service_path), kFakeServiceUuid,
             true, std::vector<dbus::ObjectPath>()));
     return full_service_path;
@@ -350,7 +350,7 @@
 
 TEST_F(BluetoothGattApplicationServiceProviderTest, GetManagedObjects) {
   std::unique_ptr<BluetoothGattApplicationServiceProviderImpl> app_provider =
-      base::MakeUnique<BluetoothGattApplicationServiceProviderImpl>(
+      std::make_unique<BluetoothGattApplicationServiceProviderImpl>(
           nullptr, dbus::ObjectPath(kAppObjectPath),
           std::map<dbus::ObjectPath, BluetoothLocalGattServiceBlueZ*>());
   CreateFakeAttributes(app_provider.get());
@@ -364,7 +364,7 @@
 
 TEST_F(BluetoothGattApplicationServiceProviderTest, SendValueChanged) {
   std::unique_ptr<BluetoothGattApplicationServiceProviderImpl> app_provider =
-      base::MakeUnique<BluetoothGattApplicationServiceProviderImpl>(
+      std::make_unique<BluetoothGattApplicationServiceProviderImpl>(
           nullptr, dbus::ObjectPath(kAppObjectPath),
           std::map<dbus::ObjectPath, BluetoothLocalGattServiceBlueZ*>());
   const std::string& kServicePath =
diff --git a/device/bluetooth/dbus/bluetooth_le_advertisement_service_provider.cc b/device/bluetooth/dbus/bluetooth_le_advertisement_service_provider.cc
index 51494bb..9b5cbff 100644
--- a/device/bluetooth/dbus/bluetooth_le_advertisement_service_provider.cc
+++ b/device/bluetooth/dbus/bluetooth_le_advertisement_service_provider.cc
@@ -422,12 +422,12 @@
     std::unique_ptr<UUIDList> solicit_uuids,
     std::unique_ptr<ServiceData> service_data) {
   if (!bluez::BluezDBusManager::Get()->IsUsingFakes()) {
-    return base::MakeUnique<BluetoothAdvertisementServiceProviderImpl>(
+    return std::make_unique<BluetoothAdvertisementServiceProviderImpl>(
         bus, object_path, delegate, type, std::move(service_uuids),
         std::move(manufacturer_data), std::move(solicit_uuids),
         std::move(service_data));
   }
-  return base::MakeUnique<FakeBluetoothLEAdvertisementServiceProvider>(
+  return std::make_unique<FakeBluetoothLEAdvertisementServiceProvider>(
       object_path, delegate);
 }
 
diff --git a/device/bluetooth/dbus/fake_bluetooth_device_client.cc b/device/bluetooth/dbus/fake_bluetooth_device_client.cc
index ae73a84f..26710672 100644
--- a/device/bluetooth/dbus/fake_bluetooth_device_client.cc
+++ b/device/bluetooth/dbus/fake_bluetooth_device_client.cc
@@ -104,29 +104,29 @@
   BluetoothDeviceClient::ServiceRecordList records;
 
   std::unique_ptr<BluetoothServiceRecordBlueZ> record1 =
-      base::MakeUnique<BluetoothServiceRecordBlueZ>();
+      std::make_unique<BluetoothServiceRecordBlueZ>();
   // ID 0 = handle.
   record1->AddRecordEntry(
       0x0, BluetoothServiceAttributeValueBlueZ(
                BluetoothServiceAttributeValueBlueZ::UINT, 4,
-               base::MakeUnique<base::Value>(static_cast<int32_t>(0x1337))));
+               std::make_unique<base::Value>(static_cast<int32_t>(0x1337))));
   // ID 1 = service class id list.
   std::unique_ptr<BluetoothServiceAttributeValueBlueZ::Sequence> class_id_list =
-      base::MakeUnique<BluetoothServiceAttributeValueBlueZ::Sequence>();
+      std::make_unique<BluetoothServiceAttributeValueBlueZ::Sequence>();
   class_id_list->emplace_back(BluetoothServiceAttributeValueBlueZ::UUID, 4,
-                              base::MakeUnique<base::Value>("1802"));
+                              std::make_unique<base::Value>("1802"));
   record1->AddRecordEntry(
       0x1, BluetoothServiceAttributeValueBlueZ(std::move(class_id_list)));
   records.emplace_back(*record1);
 
   std::unique_ptr<BluetoothServiceRecordBlueZ> record2 =
-      base::MakeUnique<BluetoothServiceRecordBlueZ>();
+      std::make_unique<BluetoothServiceRecordBlueZ>();
   // ID 0 = handle.
   record2->AddRecordEntry(
       0x0,
       BluetoothServiceAttributeValueBlueZ(
           BluetoothServiceAttributeValueBlueZ::UINT, 4,
-          base::MakeUnique<base::Value>(static_cast<int32_t>(0xffffffff))));
+          std::make_unique<base::Value>(static_cast<int32_t>(0xffffffff))));
   records.emplace_back(*record2);
 
   return records;
diff --git a/device/bluetooth/dbus/fake_bluetooth_input_client.cc b/device/bluetooth/dbus/fake_bluetooth_input_client.cc
index f7f7baa..699e417 100644
--- a/device/bluetooth/dbus/fake_bluetooth_input_client.cc
+++ b/device/bluetooth/dbus/fake_bluetooth_input_client.cc
@@ -71,7 +71,7 @@
   if (properties_map_.find(object_path) != properties_map_.end())
     return;
 
-  std::unique_ptr<Properties> properties = base::MakeUnique<Properties>(
+  std::unique_ptr<Properties> properties = std::make_unique<Properties>(
       base::Bind(&FakeBluetoothInputClient::OnPropertyChanged,
                  base::Unretained(this), object_path));
 
diff --git a/device/bluetooth/dbus/fake_bluetooth_media_transport_client.cc b/device/bluetooth/dbus/fake_bluetooth_media_transport_client.cc
index ae6754e..3c5b825 100644
--- a/device/bluetooth/dbus/fake_bluetooth_media_transport_client.cc
+++ b/device/bluetooth/dbus/fake_bluetooth_media_transport_client.cc
@@ -178,7 +178,7 @@
     properties->volume.ReplaceValue(kTransportVolume);
 
     endpoint_to_transport_map_[endpoint_path] =
-        base::MakeUnique<Transport>(transport_path, std::move(properties));
+        std::make_unique<Transport>(transport_path, std::move(properties));
     transport_to_endpoint_map_[transport_path] = endpoint_path;
     return;
   }
diff --git a/device/bluetooth/device_unittest.cc b/device/bluetooth/device_unittest.cc
index 9a07564..1292882 100644
--- a/device/bluetooth/device_unittest.cc
+++ b/device/bluetooth/device_unittest.cc
@@ -76,18 +76,18 @@
     ON_CALL(*adapter_, GetDevice(kTestLeDeviceAddress0))
         .WillByDefault(Return(&device_));
 
-    auto service1 = base::MakeUnique<NiceMockBluetoothGattService>(
+    auto service1 = std::make_unique<NiceMockBluetoothGattService>(
         &device_, kTestServiceId0, device::BluetoothUUID(kTestServiceUuid0),
         true /* is_primary */, false /* is_local */);
 
     auto characteristic1 =
-        base::MakeUnique<NiceMockBluetoothGattCharacteristic>(
+        std::make_unique<NiceMockBluetoothGattCharacteristic>(
             service1.get(), kTestCharacteristicId0,
             device::BluetoothUUID(kTestCharacteristicUuid0),
             false /* is_local */, kReadWriteProperties, 0 /* permissions */);
 
     auto characteristic2 =
-        base::MakeUnique<NiceMockBluetoothGattCharacteristic>(
+        std::make_unique<NiceMockBluetoothGattCharacteristic>(
             service1.get(), kTestCharacteristicId1,
             device::BluetoothUUID(kTestCharacteristicUuid1),
             false /* is_local */, kReadWriteProperties, 0 /* permissions */);
@@ -95,12 +95,12 @@
     service1->AddMockCharacteristic(std::move(characteristic1));
     service1->AddMockCharacteristic(std::move(characteristic2));
 
-    auto service2 = base::MakeUnique<NiceMockBluetoothGattService>(
+    auto service2 = std::make_unique<NiceMockBluetoothGattService>(
         &device_, kTestServiceId1, device::BluetoothUUID(kTestServiceUuid1),
         true /* is_primary */, false /* is_local */);
 
     auto characteristic3 =
-        base::MakeUnique<NiceMockBluetoothGattCharacteristic>(
+        std::make_unique<NiceMockBluetoothGattCharacteristic>(
             service2.get(), kTestCharacteristicId2,
             device::BluetoothUUID(kTestCharacteristicUuid2),
             false /* is_local */, kAllProperties, 0 /* permissions */);
@@ -128,7 +128,7 @@
         .WillRepeatedly(
             Invoke(&device_, &device::MockBluetoothDevice::GetMockService));
 
-    auto connection = base::MakeUnique<NiceMockBluetoothGattConnection>(
+    auto connection = std::make_unique<NiceMockBluetoothGattConnection>(
         adapter_, device_.GetAddress());
 
     Device::Create(adapter_, std::move(connection), mojo::MakeRequest(&proxy_));
diff --git a/device/bluetooth/test/bluetooth_gatt_server_test.cc b/device/bluetooth/test/bluetooth_gatt_server_test.cc
index 508dc2b..b146f597 100644
--- a/device/bluetooth/test/bluetooth_gatt_server_test.cc
+++ b/device/bluetooth/test/bluetooth_gatt_server_test.cc
@@ -32,7 +32,7 @@
   BluetoothTest::SetUp();
   last_read_value_ = std::vector<uint8_t>();
   InitWithFakeAdapter();
-  delegate_ = base::MakeUnique<TestBluetoothLocalGattServiceDelegate>();
+  delegate_ = std::make_unique<TestBluetoothLocalGattServiceDelegate>();
 }
 
 void BluetoothGattServerTest::TearDown() {
diff --git a/device/bluetooth/test/bluetooth_test.cc b/device/bluetooth/test/bluetooth_test.cc
index 82d2146..5a0f19a 100644
--- a/device/bluetooth/test/bluetooth_test.cc
+++ b/device/bluetooth/test/bluetooth_test.cc
@@ -64,7 +64,7 @@
 
 void BluetoothTestBase::StartLowEnergyDiscoverySession() {
   adapter_->StartDiscoverySessionWithFilter(
-      base::MakeUnique<BluetoothDiscoveryFilter>(BLUETOOTH_TRANSPORT_LE),
+      std::make_unique<BluetoothDiscoveryFilter>(BLUETOOTH_TRANSPORT_LE),
       GetDiscoverySessionCallback(Call::EXPECTED),
       GetErrorCallback(Call::NOT_EXPECTED));
   base::RunLoop().RunUntilIdle();
@@ -72,7 +72,7 @@
 
 void BluetoothTestBase::StartLowEnergyDiscoverySessionExpectedToFail() {
   adapter_->StartDiscoverySessionWithFilter(
-      base::MakeUnique<BluetoothDiscoveryFilter>(BLUETOOTH_TRANSPORT_LE),
+      std::make_unique<BluetoothDiscoveryFilter>(BLUETOOTH_TRANSPORT_LE),
       GetDiscoverySessionCallback(Call::NOT_EXPECTED),
       GetErrorCallback(Call::EXPECTED));
   base::RunLoop().RunUntilIdle();
diff --git a/device/bluetooth/test/fake_bluetooth.cc b/device/bluetooth/test/fake_bluetooth.cc
index 79980d8..0415676 100644
--- a/device/bluetooth/test/fake_bluetooth.cc
+++ b/device/bluetooth/test/fake_bluetooth.cc
@@ -22,7 +22,7 @@
 
 // static
 void FakeBluetooth::Create(mojom::FakeBluetoothRequest request) {
-  mojo::MakeStrongBinding(base::MakeUnique<FakeBluetooth>(),
+  mojo::MakeStrongBinding(std::make_unique<FakeBluetooth>(),
                           std::move(request));
 }
 
diff --git a/device/bluetooth/test/fake_central.cc b/device/bluetooth/test/fake_central.cc
index 9f0bc62..0761ccd7e 100644
--- a/device/bluetooth/test/fake_central.cc
+++ b/device/bluetooth/test/fake_central.cc
@@ -30,7 +30,7 @@
     SimulatePreconnectedPeripheralCallback callback) {
   FakePeripheral* fake_peripheral = GetFakePeripheral(address);
   if (fake_peripheral == nullptr) {
-    auto fake_peripheral_ptr = base::MakeUnique<FakePeripheral>(this, address);
+    auto fake_peripheral_ptr = std::make_unique<FakePeripheral>(this, address);
     fake_peripheral = fake_peripheral_ptr.get();
     auto pair = devices_.emplace(address, std::move(fake_peripheral_ptr));
     DCHECK(pair.second);
diff --git a/device/bluetooth/test/fake_peripheral.cc b/device/bluetooth/test/fake_peripheral.cc
index 364db3e..88555ac 100644
--- a/device/bluetooth/test/fake_peripheral.cc
+++ b/device/bluetooth/test/fake_peripheral.cc
@@ -60,7 +60,7 @@
 
   std::tie(it, inserted) = gatt_services_.emplace(
       new_service_id,
-      base::MakeUnique<FakeRemoteGattService>(new_service_id, service_uuid,
+      std::make_unique<FakeRemoteGattService>(new_service_id, service_uuid,
                                               true /* is_primary */, this));
 
   DCHECK(inserted);
diff --git a/device/bluetooth/test/fake_remote_gatt_characteristic.cc b/device/bluetooth/test/fake_remote_gatt_characteristic.cc
index d3f9ffc2..aaabac1 100644
--- a/device/bluetooth/test/fake_remote_gatt_characteristic.cc
+++ b/device/bluetooth/test/fake_remote_gatt_characteristic.cc
@@ -55,7 +55,7 @@
       "%s_%zu", GetIdentifier().c_str(), ++last_descriptor_id_);
 
   std::tie(it, inserted) = fake_descriptors_.emplace(
-      new_descriptor_id, base::MakeUnique<FakeRemoteGattDescriptor>(
+      new_descriptor_id, std::make_unique<FakeRemoteGattDescriptor>(
                              new_descriptor_id, descriptor_uuid, this));
 
   DCHECK(inserted);
diff --git a/device/bluetooth/test/fake_remote_gatt_service.cc b/device/bluetooth/test/fake_remote_gatt_service.cc
index 4b4e593..a0ff9b2 100644
--- a/device/bluetooth/test/fake_remote_gatt_service.cc
+++ b/device/bluetooth/test/fake_remote_gatt_service.cc
@@ -42,7 +42,7 @@
       "%s_%zu", GetIdentifier().c_str(), ++last_characteristic_id_);
 
   std::tie(it, inserted) = fake_characteristics_.emplace(
-      new_characteristic_id, base::MakeUnique<FakeRemoteGattCharacteristic>(
+      new_characteristic_id, std::make_unique<FakeRemoteGattCharacteristic>(
                                  new_characteristic_id, characteristic_uuid,
                                  std::move(properties), this));
 
diff --git a/device/gamepad/gamepad_monitor.cc b/device/gamepad/gamepad_monitor.cc
index 8e3144e4..f15ee20 100644
--- a/device/gamepad/gamepad_monitor.cc
+++ b/device/gamepad/gamepad_monitor.cc
@@ -23,7 +23,7 @@
 
 // static
 void GamepadMonitor::Create(mojom::GamepadMonitorRequest request) {
-  mojo::MakeStrongBinding(base::MakeUnique<GamepadMonitor>(),
+  mojo::MakeStrongBinding(std::make_unique<GamepadMonitor>(),
                           std::move(request));
 }
 
diff --git a/device/geolocation/geolocation_config.cc b/device/geolocation/geolocation_config.cc
index b8e3b40..b7dd98c9 100644
--- a/device/geolocation/geolocation_config.cc
+++ b/device/geolocation/geolocation_config.cc
@@ -17,7 +17,7 @@
 void GeolocationConfig::Create(
     mojom::GeolocationConfigRequest request,
     const service_manager::BindSourceInfo& source_info) {
-  mojo::MakeStrongBinding(base::MakeUnique<GeolocationConfig>(),
+  mojo::MakeStrongBinding(std::make_unique<GeolocationConfig>(),
                           std::move(request));
 }
 
diff --git a/device/geolocation/geolocation_impl.h b/device/geolocation/geolocation_impl.h
index 187393a6..067162bc 100644
--- a/device/geolocation/geolocation_impl.h
+++ b/device/geolocation/geolocation_impl.h
@@ -20,9 +20,7 @@
 // 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.
+  // |context| must outlive this object.
   GeolocationImpl(mojo::InterfaceRequest<mojom::Geolocation> request,
                   GeolocationContext* context);
   ~GeolocationImpl() override;
@@ -53,6 +51,8 @@
 
   // Owns this object.
   GeolocationContext* context_;
+
+  // Token that unsubscribes from GeolocationProvider updates when destroyed.
   std::unique_ptr<GeolocationProvider::Subscription> geolocation_subscription_;
 
   // The callback passed to QueryNextPosition.
diff --git a/device/geolocation/geolocation_provider_impl.cc b/device/geolocation/geolocation_provider_impl.cc
index 9cba7692..3ea97c9 100644
--- a/device/geolocation/geolocation_provider_impl.cc
+++ b/device/geolocation/geolocation_provider_impl.cc
@@ -194,7 +194,7 @@
     if (!g_delegate.Get())
       g_delegate.Get().reset(new GeolocationDelegate);
 
-    arbitrator_ = base::MakeUnique<LocationArbitrator>(
+    arbitrator_ = std::make_unique<LocationArbitrator>(
         base::WrapUnique(g_delegate.Get().get()));
     arbitrator_->SetUpdateCallback(callback);
   }
diff --git a/device/geolocation/location_arbitrator.cc b/device/geolocation/location_arbitrator.cc
index 2a2774b..6267e5a 100644
--- a/device/geolocation/location_arbitrator.cc
+++ b/device/geolocation/location_arbitrator.cc
@@ -175,7 +175,7 @@
   // Android uses its own SystemLocationProvider.
   return nullptr;
 #else
-  return base::MakeUnique<NetworkLocationProvider>(access_token_store, context,
+  return std::make_unique<NetworkLocationProvider>(access_token_store, context,
                                                    url, access_token);
 #endif
 }
diff --git a/device/geolocation/network_location_request.cc b/device/geolocation/network_location_request.cc
index 22fe1dd..9cd3ad2 100644
--- a/device/geolocation/network_location_request.cc
+++ b/device/geolocation/network_location_request.cc
@@ -276,9 +276,9 @@
   for (const auto& ap_data : wifi_data.access_point_data)
     access_points_by_signal_strength.insert(&ap_data);
 
-  auto wifi_access_point_list = base::MakeUnique<base::ListValue>();
+  auto wifi_access_point_list = std::make_unique<base::ListValue>();
   for (auto* ap_data : access_points_by_signal_strength) {
-    auto wifi_dict = base::MakeUnique<base::DictionaryValue>();
+    auto wifi_dict = std::make_unique<base::DictionaryValue>();
     AddString("macAddress", base::UTF16ToUTF8(ap_data->mac_address),
               wifi_dict.get());
     AddInteger("signalStrength", ap_data->radio_signal_strength,
diff --git a/device/geolocation/wifi_data_provider_linux.cc b/device/geolocation/wifi_data_provider_linux.cc
index 832672c5..4c41dc5 100644
--- a/device/geolocation/wifi_data_provider_linux.cc
+++ b/device/geolocation/wifi_data_provider_linux.cc
@@ -354,7 +354,7 @@
 
 std::unique_ptr<WifiPollingPolicy>
 WifiDataProviderLinux::CreatePollingPolicy() {
-  return base::MakeUnique<GenericWifiPollingPolicy<
+  return std::make_unique<GenericWifiPollingPolicy<
       kDefaultPollingIntervalMilliseconds, kNoChangePollingIntervalMilliseconds,
       kTwoNoChangePollingIntervalMilliseconds,
       kNoWifiPollingIntervalMilliseconds>>();
diff --git a/device/geolocation/wifi_data_provider_mac.mm b/device/geolocation/wifi_data_provider_mac.mm
index 6edf179..dd5492d 100644
--- a/device/geolocation/wifi_data_provider_mac.mm
+++ b/device/geolocation/wifi_data_provider_mac.mm
@@ -125,11 +125,11 @@
 
 std::unique_ptr<WifiDataProviderMac::WlanApiInterface>
 WifiDataProviderMac::CreateWlanApi() {
-  return base::MakeUnique<CoreWlanApi>();
+  return std::make_unique<CoreWlanApi>();
 }
 
 std::unique_ptr<WifiPollingPolicy> WifiDataProviderMac::CreatePollingPolicy() {
-  return base::MakeUnique<GenericWifiPollingPolicy<
+  return std::make_unique<GenericWifiPollingPolicy<
       kDefaultPollingInterval, kNoChangePollingInterval,
       kTwoNoChangePollingInterval, kNoWifiPollingIntervalMilliseconds>>();
 }
diff --git a/device/geolocation/wifi_data_provider_win.cc b/device/geolocation/wifi_data_provider_win.cc
index 908d06c..c3c2821 100644
--- a/device/geolocation/wifi_data_provider_win.cc
+++ b/device/geolocation/wifi_data_provider_win.cc
@@ -117,7 +117,7 @@
   HINSTANCE library = LoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
   if (!library)
     return nullptr;
-  return base::MakeUnique<WindowsWlanApi>(library);
+  return std::make_unique<WindowsWlanApi>(library);
 }
 
 WindowsWlanApi::WindowsWlanApi(HINSTANCE library) : library_(library) {
@@ -248,7 +248,7 @@
 }
 
 std::unique_ptr<WifiPollingPolicy> WifiDataProviderWin::CreatePollingPolicy() {
-  return base::MakeUnique<GenericWifiPollingPolicy<
+  return std::make_unique<GenericWifiPollingPolicy<
       kDefaultPollingIntervalMs, kNoChangePollingIntervalMs,
       kTwoNoChangePollingIntervalMs, kNoWifiPollingIntervalMs>>();
 }
diff --git a/device/hid/hid_connection_linux.cc b/device/hid/hid_connection_linux.cc
index de20ed7..8824fce 100644
--- a/device/hid/hid_connection_linux.cc
+++ b/device/hid/hid_connection_linux.cc
@@ -174,7 +174,7 @@
     : HidConnection(device_info),
       blocking_task_runner_(std::move(blocking_task_runner)),
       weak_factory_(this) {
-  helper_ = base::MakeUnique<BlockingTaskHelper>(std::move(fd), device_info,
+  helper_ = std::make_unique<BlockingTaskHelper>(std::move(fd), device_info,
                                                  weak_factory_.GetWeakPtr());
   blocking_task_runner_->PostTask(
       FROM_HERE, base::BindOnce(&BlockingTaskHelper::Start,
diff --git a/device/hid/hid_connection_win.cc b/device/hid/hid_connection_win.cc
index b79b9598..3b3b983b 100644
--- a/device/hid/hid_connection_win.cc
+++ b/device/hid/hid_connection_win.cc
@@ -104,7 +104,7 @@
   // are not in use) in the buffer.
   scoped_refptr<net::IOBufferWithSize> buffer = new net::IOBufferWithSize(
       base::checked_cast<int>(device_info()->max_input_report_size() + 1));
-  transfers_.push_back(base::MakeUnique<PendingHidTransfer>(
+  transfers_.push_back(std::make_unique<PendingHidTransfer>(
       buffer, base::BindOnce(&HidConnectionWin::OnReadComplete, this, buffer,
                              std::move(callback))));
   transfers_.back()->TakeResultFromWindowsAPI(
@@ -128,7 +128,7 @@
     buffer = tmp_buffer;
     size = expected_size;
   }
-  transfers_.push_back(base::MakeUnique<PendingHidTransfer>(
+  transfers_.push_back(std::make_unique<PendingHidTransfer>(
       buffer, base::BindOnce(&HidConnectionWin::OnWriteComplete, this,
                              std::move(callback))));
   transfers_.back()->TakeResultFromWindowsAPI(
@@ -143,7 +143,7 @@
       base::checked_cast<int>(device_info()->max_feature_report_size() + 1));
   buffer->data()[0] = report_id;
 
-  transfers_.push_back(base::MakeUnique<PendingHidTransfer>(
+  transfers_.push_back(std::make_unique<PendingHidTransfer>(
       buffer, base::BindOnce(&HidConnectionWin::OnReadFeatureComplete, this,
                              buffer, std::move(callback))));
   transfers_.back()->TakeResultFromWindowsAPI(
@@ -158,7 +158,7 @@
     WriteCallback callback) {
   // The Windows API always wants either a report ID (if supported) or
   // zero at the front of every output report.
-  transfers_.push_back(base::MakeUnique<PendingHidTransfer>(
+  transfers_.push_back(std::make_unique<PendingHidTransfer>(
       buffer, base::BindOnce(&HidConnectionWin::OnWriteComplete, this,
                              std::move(callback))));
   transfers_.back()->TakeResultFromWindowsAPI(
diff --git a/device/hid/hid_service_linux.cc b/device/hid/hid_service_linux.cc
index 4dd8769..ede6113 100644
--- a/device/hid/hid_service_linux.cc
+++ b/device/hid/hid_service_linux.cc
@@ -190,7 +190,7 @@
     : blocking_task_runner_(
           base::CreateSequencedTaskRunnerWithTraits(kBlockingTaskTraits)),
       weak_factory_(this) {
-  helper_ = base::MakeUnique<BlockingTaskHelper>(weak_factory_.GetWeakPtr());
+  helper_ = std::make_unique<BlockingTaskHelper>(weak_factory_.GetWeakPtr());
   blocking_task_runner_->PostTask(
       FROM_HERE,
       base::Bind(&BlockingTaskHelper::Start, base::Unretained(helper_.get())));
@@ -217,7 +217,7 @@
   scoped_refptr<HidDeviceInfoLinux> device_info =
       static_cast<HidDeviceInfoLinux*>(map_entry->second.get());
 
-  auto params = base::MakeUnique<ConnectParams>(device_info, callback);
+  auto params = std::make_unique<ConnectParams>(device_info, callback);
 
 #if defined(OS_CHROMEOS)
   chromeos::PermissionBrokerClient* client =
diff --git a/device/test/usb_test_gadget_impl.cc b/device/test/usb_test_gadget_impl.cc
index 2324cd6..c3f69a3c 100644
--- a/device/test/usb_test_gadget_impl.cc
+++ b/device/test/usb_test_gadget_impl.cc
@@ -220,7 +220,7 @@
   std::unique_ptr<UsbTestGadget> WaitForDevice() {
     EnumerateDevices();
     run_loop_.Run();
-    return base::MakeUnique<UsbTestGadgetImpl>(request_context_getter_,
+    return std::make_unique<UsbTestGadgetImpl>(request_context_getter_,
                                                usb_service_, device_);
   }
 
diff --git a/device/u2f/mock_u2f_device.cc b/device/u2f/mock_u2f_device.cc
index e833bbf6..ac14cca 100644
--- a/device/u2f/mock_u2f_device.cc
+++ b/device/u2f/mock_u2f_device.cc
@@ -18,7 +18,7 @@
 // static
 void MockU2fDevice::NotSatisfied(U2fApduCommand* cmd,
                                  const DeviceCallback& cb) {
-  cb.Run(true, base::MakeUnique<U2fApduResponse>(
+  cb.Run(true, std::make_unique<U2fApduResponse>(
                    std::vector<uint8_t>(),
                    U2fApduResponse::Status::SW_CONDITIONS_NOT_SATISFIED));
 }
@@ -26,13 +26,13 @@
 // static
 void MockU2fDevice::WrongData(U2fApduCommand* cmd, const DeviceCallback& cb) {
   cb.Run(true,
-         base::MakeUnique<U2fApduResponse>(
+         std::make_unique<U2fApduResponse>(
              std::vector<uint8_t>(), U2fApduResponse::Status::SW_WRONG_DATA));
 }
 
 // static
 void MockU2fDevice::NoErrorSign(U2fApduCommand* cmd, const DeviceCallback& cb) {
-  cb.Run(true, base::MakeUnique<U2fApduResponse>(
+  cb.Run(true, std::make_unique<U2fApduResponse>(
                    std::vector<uint8_t>({kSign}),
                    U2fApduResponse::Status::SW_NO_ERROR));
 }
@@ -40,7 +40,7 @@
 // static
 void MockU2fDevice::NoErrorRegister(U2fApduCommand* cmd,
                                     const DeviceCallback& cb) {
-  cb.Run(true, base::MakeUnique<U2fApduResponse>(
+  cb.Run(true, std::make_unique<U2fApduResponse>(
                    std::vector<uint8_t>({kRegister}),
                    U2fApduResponse::Status::SW_NO_ERROR));
 }
diff --git a/device/u2f/u2f_apdu_command.cc b/device/u2f/u2f_apdu_command.cc
index a062f177..7336b116 100644
--- a/device/u2f/u2f_apdu_command.cc
+++ b/device/u2f/u2f_apdu_command.cc
@@ -73,7 +73,7 @@
       break;
   }
 
-  return base::MakeUnique<U2fApduCommand>(cla, ins, p1, p2, response_length,
+  return std::make_unique<U2fApduCommand>(cla, ins, p1, p2, response_length,
                                           std::move(data), std::move(suffix));
 }
 
@@ -135,7 +135,7 @@
     return nullptr;
   }
 
-  auto command = base::MakeUnique<U2fApduCommand>();
+  auto command = std::make_unique<U2fApduCommand>();
   std::vector<uint8_t> data(challenge_digest.begin(), challenge_digest.end());
   data.insert(data.end(), appid_digest.begin(), appid_digest.end());
   command->set_ins(kInsU2fEnroll);
@@ -146,7 +146,7 @@
 
 // static
 std::unique_ptr<U2fApduCommand> U2fApduCommand::CreateVersion() {
-  auto command = base::MakeUnique<U2fApduCommand>();
+  auto command = std::make_unique<U2fApduCommand>();
   command->set_ins(kInsU2fVersion);
   command->set_response_length(kApduMaxResponseLength);
   return command;
@@ -154,7 +154,7 @@
 
 // static
 std::unique_ptr<U2fApduCommand> U2fApduCommand::CreateLegacyVersion() {
-  auto command = base::MakeUnique<U2fApduCommand>();
+  auto command = std::make_unique<U2fApduCommand>();
   command->set_ins(kInsU2fVersion);
   command->set_response_length(kApduMaxResponseLength);
   // Early U2F drafts defined the U2F version command in extended
@@ -175,7 +175,7 @@
     return nullptr;
   }
 
-  auto command = base::MakeUnique<U2fApduCommand>();
+  auto command = std::make_unique<U2fApduCommand>();
   std::vector<uint8_t> data(challenge_digest.begin(), challenge_digest.end());
   data.insert(data.end(), appid_digest.begin(), appid_digest.end());
   data.push_back(static_cast<uint8_t>(key_handle.size()));
diff --git a/device/u2f/u2f_apdu_response.cc b/device/u2f/u2f_apdu_response.cc
index 30336d52..d418c5e 100644
--- a/device/u2f/u2f_apdu_response.cc
+++ b/device/u2f/u2f_apdu_response.cc
@@ -20,7 +20,7 @@
   response_status = static_cast<Status>(status_bytes);
   std::vector<uint8_t> data(message.begin(), message.end() - 2);
 
-  return base::MakeUnique<U2fApduResponse>(std::move(data), response_status);
+  return std::make_unique<U2fApduResponse>(std::move(data), response_status);
 }
 
 U2fApduResponse::U2fApduResponse(std::vector<uint8_t> message,
diff --git a/device/u2f/u2f_apdu_unittest.cc b/device/u2f/u2f_apdu_unittest.cc
index 4d83950..285539ae 100644
--- a/device/u2f/u2f_apdu_unittest.cc
+++ b/device/u2f/u2f_apdu_unittest.cc
@@ -112,7 +112,7 @@
 }
 
 TEST_F(U2fApduTest, TestSerializeCommand) {
-  auto cmd = base::MakeUnique<U2fApduCommand>();
+  auto cmd = std::make_unique<U2fApduCommand>();
 
   cmd->set_cla(0xA);
   cmd->set_ins(0xB);
@@ -158,7 +158,7 @@
 }
 
 TEST_F(U2fApduTest, TestSerializeEdgeCases) {
-  auto cmd = base::MakeUnique<U2fApduCommand>();
+  auto cmd = std::make_unique<U2fApduCommand>();
 
   cmd->set_cla(0xA);
   cmd->set_ins(0xB);
diff --git a/device/u2f/u2f_hid_device_unittest.cc b/device/u2f/u2f_hid_device_unittest.cc
index 6da3b79..fab33990 100644
--- a/device/u2f/u2f_hid_device_unittest.cc
+++ b/device/u2f/u2f_hid_device_unittest.cc
@@ -80,7 +80,7 @@
     filter_.SetUsagePage(0xf1d0);
     for (auto device_info : devices) {
       if (filter_.Matches(device_info))
-        u2f_devices.push_front(base::MakeUnique<U2fHidDevice>(device_info));
+        u2f_devices.push_front(std::make_unique<U2fHidDevice>(device_info));
     }
     devices_ = std::move(u2f_devices);
     closure_.Run();
@@ -215,7 +215,7 @@
 
 TEST_F(U2fHidDeviceTest, TestConnectionFailure) {
   // Setup and enumerate mock device
-  auto client = base::MakeUnique<MockDeviceClient>();
+  auto client = std::make_unique<MockDeviceClient>();
   U2fDeviceEnumerate callback;
   MockHidService* hid_service = client->hid_service();
   HidCollectionInfo c_info;
@@ -260,7 +260,7 @@
 
 TEST_F(U2fHidDeviceTest, TestDeviceError) {
   // Setup and enumerate mock device
-  auto client = base::MakeUnique<MockDeviceClient>();
+  auto client = std::make_unique<MockDeviceClient>();
   U2fDeviceEnumerate callback;
   MockHidService* hid_service = client->hid_service();
   HidCollectionInfo c_info;
diff --git a/device/u2f/u2f_message.cc b/device/u2f/u2f_message.cc
index 0778025..ea309467 100644
--- a/device/u2f/u2f_message.cc
+++ b/device/u2f/u2f_message.cc
@@ -18,7 +18,7 @@
   if (data.size() > kMaxMessageSize)
     return nullptr;
 
-  return base::MakeUnique<U2fMessage>(channel_id, type, data);
+  return std::make_unique<U2fMessage>(channel_id, type, data);
 }
 
 // static
@@ -33,7 +33,7 @@
   if (init_packet == nullptr)
     return nullptr;
 
-  return base::MakeUnique<U2fMessage>(std::move(init_packet), remaining_size);
+  return std::make_unique<U2fMessage>(std::move(init_packet), remaining_size);
 }
 
 U2fMessage::U2fMessage(std::unique_ptr<U2fInitPacket> init_packet,
@@ -61,7 +61,7 @@
     remaining_bytes = 0;
   }
 
-  packets_.push_back(base::MakeUnique<U2fInitPacket>(
+  packets_.push_back(std::make_unique<U2fInitPacket>(
       channel_id, static_cast<uint8_t>(type), std::vector<uint8_t>(first, last),
       data.size()));
 
@@ -75,7 +75,7 @@
       remaining_bytes = 0;
     }
 
-    packets_.push_back(base::MakeUnique<U2fContinuationPacket>(
+    packets_.push_back(std::make_unique<U2fContinuationPacket>(
         channel_id, sequence, std::vector<uint8_t>(first, last)));
     sequence++;
   }
diff --git a/device/u2f/u2f_message_unittest.cc b/device/u2f/u2f_message_unittest.cc
index 59f52c55..7fabd6d 100644
--- a/device/u2f/u2f_message_unittest.cc
+++ b/device/u2f/u2f_message_unittest.cc
@@ -18,11 +18,11 @@
   std::vector<uint8_t> data;
 
   auto init_packet =
-      base::MakeUnique<U2fInitPacket>(channel_id, 0, data, data.size());
+      std::make_unique<U2fInitPacket>(channel_id, 0, data, data.size());
   EXPECT_EQ(65, init_packet->GetSerializedData()->size());
 
   auto continuation_packet =
-      base::MakeUnique<U2fContinuationPacket>(channel_id, 0, data);
+      std::make_unique<U2fContinuationPacket>(channel_id, 0, data);
   EXPECT_EQ(65, continuation_packet->GetSerializedData()->size());
 }
 
@@ -41,7 +41,7 @@
   std::vector<uint8_t> data{10, 11};
   uint8_t cmd = static_cast<uint8_t>(U2fMessage::Type::CMD_WINK);
   auto init_packet =
-      base::MakeUnique<U2fInitPacket>(channel_id, cmd, data, data.size());
+      std::make_unique<U2fInitPacket>(channel_id, cmd, data, data.size());
   int index = 0;
 
   scoped_refptr<net::IOBufferWithSize> serialized =
@@ -72,7 +72,7 @@
   std::vector<uint8_t> data{10, 11};
   uint8_t cmd = static_cast<uint8_t>(U2fMessage::Type::CMD_WINK);
   auto orig_packet =
-      base::MakeUnique<U2fInitPacket>(channel_id, cmd, data, data.size());
+      std::make_unique<U2fInitPacket>(channel_id, cmd, data, data.size());
 
   size_t payload_length = static_cast<size_t>(orig_packet->payload_length());
   scoped_refptr<net::IOBufferWithSize> buffer =
diff --git a/device/u2f/u2f_packet.cc b/device/u2f/u2f_packet.cc
index 15eb47c..34549228 100644
--- a/device/u2f/u2f_packet.cc
+++ b/device/u2f/u2f_packet.cc
@@ -64,7 +64,7 @@
   if (remaining_size == nullptr || serialized.size() != kPacketSize)
     return nullptr;
 
-  return base::MakeUnique<U2fInitPacket>(serialized, remaining_size);
+  return std::make_unique<U2fInitPacket>(serialized, remaining_size);
 }
 
 U2fInitPacket::U2fInitPacket(const std::vector<uint8_t>& serialized,
@@ -131,7 +131,7 @@
   if (remaining_size == nullptr || serialized.size() != kPacketSize)
     return nullptr;
 
-  return base::MakeUnique<U2fContinuationPacket>(serialized, remaining_size);
+  return std::make_unique<U2fContinuationPacket>(serialized, remaining_size);
 }
 
 U2fContinuationPacket::U2fContinuationPacket(
diff --git a/device/u2f/u2f_register.cc b/device/u2f/u2f_register.cc
index babfe98..ae7b7d42 100644
--- a/device/u2f/u2f_register.cc
+++ b/device/u2f/u2f_register.cc
@@ -24,7 +24,7 @@
     const std::vector<uint8_t>& app_param,
     const ResponseCallback& cb) {
   std::unique_ptr<U2fRequest> request =
-      base::MakeUnique<U2fRegister>(challenge_hash, app_param, cb);
+      std::make_unique<U2fRegister>(challenge_hash, app_param, cb);
   request->Start();
   return request;
 }
diff --git a/device/u2f/u2f_request.cc b/device/u2f/u2f_request.cc
index 23d5ca15..efd470b 100644
--- a/device/u2f/u2f_request.cc
+++ b/device/u2f/u2f_request.cc
@@ -60,7 +60,7 @@
     const std::vector<scoped_refptr<HidDeviceInfo>>& devices) {
   for (auto device_info : devices) {
     if (filter_.Matches(device_info))
-      devices_.push_back(base::MakeUnique<U2fHidDevice>(device_info));
+      devices_.push_back(std::make_unique<U2fHidDevice>(device_info));
   }
 
   hid_service_observer_.Add(hid_service);
@@ -74,7 +74,7 @@
   if (!filter_.Matches(device_info))
     return;
 
-  auto device = base::MakeUnique<U2fHidDevice>(device_info);
+  auto device = std::make_unique<U2fHidDevice>(device_info);
   AddDevice(std::move(device));
 }
 
@@ -83,7 +83,7 @@
   if (!filter_.Matches(device_info))
     return;
 
-  auto device = base::MakeUnique<U2fHidDevice>(device_info);
+  auto device = std::make_unique<U2fHidDevice>(device_info);
 
   // Check if the active device was removed
   if (current_device_ && current_device_->GetId() == device->GetId()) {
diff --git a/device/u2f/u2f_request_unittest.cc b/device/u2f/u2f_request_unittest.cc
index 506d85f2..dab7e92 100644
--- a/device/u2f/u2f_request_unittest.cc
+++ b/device/u2f/u2f_request_unittest.cc
@@ -129,11 +129,11 @@
   scoped_refptr<HidDeviceInfo> device0 = make_scoped_refptr(
       new HidDeviceInfo(kTestDeviceId0, 0, 0, "Test Fido Device", "123FIDO",
                         kHIDBusTypeUSB, c_info, 64, 64, 0));
-  request.devices_.push_back(base::MakeUnique<U2fHidDevice>(device0));
+  request.devices_.push_back(std::make_unique<U2fHidDevice>(device0));
   scoped_refptr<HidDeviceInfo> device1 = make_scoped_refptr(
       new HidDeviceInfo(kTestDeviceId1, 0, 0, "Test Fido Device", "123FIDO",
                         kHIDBusTypeUSB, c_info, 64, 64, 0));
-  request.devices_.push_back(base::MakeUnique<U2fHidDevice>(device1));
+  request.devices_.push_back(std::make_unique<U2fHidDevice>(device1));
 
   // Move first device to current
   request.IterateDevice();
diff --git a/device/u2f/u2f_sign.cc b/device/u2f/u2f_sign.cc
index a1f5b7d..efa7136 100644
--- a/device/u2f/u2f_sign.cc
+++ b/device/u2f/u2f_sign.cc
@@ -27,7 +27,7 @@
     const std::vector<uint8_t>& app_param,
     const ResponseCallback& cb) {
   std::unique_ptr<U2fRequest> request =
-      base::MakeUnique<U2fSign>(registered_keys, challenge_hash, app_param, cb);
+      std::make_unique<U2fSign>(registered_keys, challenge_hash, app_param, cb);
   request->Start();
   return request;
 }
diff --git a/device/usb/usb_device_handle_win.cc b/device/usb/usb_device_handle_win.cc
index 30044da..6ed5484e 100644
--- a/device/usb/usb_device_handle_win.cc
+++ b/device/usb/usb_device_handle_win.cc
@@ -282,7 +282,7 @@
 UsbDeviceHandleWin::~UsbDeviceHandleWin() {}
 
 UsbDeviceHandleWin::Request* UsbDeviceHandleWin::MakeRequest(HANDLE handle) {
-  auto request = base::MakeUnique<Request>(hub_handle_.Get());
+  auto request = std::make_unique<Request>(hub_handle_.Get());
   Request* request_ptr = request.get();
   requests_[request_ptr] = std::move(request);
   return request_ptr;
diff --git a/device/usb/usb_device_win.cc b/device/usb/usb_device_win.cc
index 87baab8..3752f31 100644
--- a/device/usb/usb_device_win.cc
+++ b/device/usb/usb_device_win.cc
@@ -69,7 +69,7 @@
 
   descriptor_ = *descriptor;
 
-  auto string_map = base::MakeUnique<std::map<uint8_t, base::string16>>();
+  auto string_map = std::make_unique<std::map<uint8_t, base::string16>>();
   if (descriptor_.i_manufacturer)
     (*string_map)[descriptor_.i_manufacturer] = base::string16();
   if (descriptor_.i_product)
diff --git a/device/usb/usb_service_linux.cc b/device/usb/usb_service_linux.cc
index e882c4d3..a366f2d 100644
--- a/device/usb/usb_service_linux.cc
+++ b/device/usb/usb_service_linux.cc
@@ -182,7 +182,7 @@
 
 UsbServiceLinux::UsbServiceLinux()
     : UsbService(CreateBlockingTaskRunner()), weak_factory_(this) {
-  helper_ = base::MakeUnique<FileThreadHelper>(weak_factory_.GetWeakPtr());
+  helper_ = std::make_unique<FileThreadHelper>(weak_factory_.GetWeakPtr());
   blocking_task_runner()->PostTask(
       FROM_HERE,
       base::Bind(&FileThreadHelper::Start, base::Unretained(helper_.get())));
diff --git a/device/usb/usb_service_win.cc b/device/usb/usb_service_win.cc
index c0b2a75e..c4cd024 100644
--- a/device/usb/usb_service_win.cc
+++ b/device/usb/usb_service_win.cc
@@ -285,7 +285,7 @@
   if (device_monitor)
     device_observer_.Add(device_monitor);
 
-  helper_ = base::MakeUnique<BlockingTaskHelper>(weak_factory_.GetWeakPtr());
+  helper_ = std::make_unique<BlockingTaskHelper>(weak_factory_.GetWeakPtr());
   blocking_task_runner()->PostTask(
       FROM_HERE, base::Bind(&BlockingTaskHelper::EnumerateDevices,
                             base::Unretained(helper_.get())));
diff --git a/device/vr/android/gvr/cardboard_gamepad_data_fetcher.cc b/device/vr/android/gvr/cardboard_gamepad_data_fetcher.cc
index 30d7a888..91b3ffb 100644
--- a/device/vr/android/gvr/cardboard_gamepad_data_fetcher.cc
+++ b/device/vr/android/gvr/cardboard_gamepad_data_fetcher.cc
@@ -37,7 +37,7 @@
 
 std::unique_ptr<GamepadDataFetcher>
 CardboardGamepadDataFetcher::Factory::CreateDataFetcher() {
-  return base::MakeUnique<CardboardGamepadDataFetcher>(data_provider_,
+  return std::make_unique<CardboardGamepadDataFetcher>(data_provider_,
                                                        display_id_);
 }
 
diff --git a/device/vr/android/gvr/gvr_device_provider.cc b/device/vr/android/gvr/gvr_device_provider.cc
index 8a9855dc..e1f37c07 100644
--- a/device/vr/android/gvr/gvr_device_provider.cc
+++ b/device/vr/android/gvr/gvr_device_provider.cc
@@ -18,7 +18,7 @@
 }
 
 void GvrDeviceProvider::Initialize() {
-  vr_device_ = base::MakeUnique<GvrDevice>();
+  vr_device_ = std::make_unique<GvrDevice>();
 }
 
 }  // namespace device
diff --git a/device/vr/android/gvr/gvr_gamepad_data_fetcher.cc b/device/vr/android/gvr/gvr_gamepad_data_fetcher.cc
index a24b4a24..c1b88d1 100644
--- a/device/vr/android/gvr/gvr_gamepad_data_fetcher.cc
+++ b/device/vr/android/gvr/gvr_gamepad_data_fetcher.cc
@@ -37,7 +37,7 @@
 
 std::unique_ptr<GamepadDataFetcher>
 GvrGamepadDataFetcher::Factory::CreateDataFetcher() {
-  return base::MakeUnique<GvrGamepadDataFetcher>(data_provider_, display_id_);
+  return std::make_unique<GvrGamepadDataFetcher>(data_provider_, display_id_);
 }
 
 GamepadSource GvrGamepadDataFetcher::Factory::source() {
diff --git a/device/vr/openvr/openvr_device.cc b/device/vr/openvr/openvr_device.cc
index 397e68f6..5f4edd2 100644
--- a/device/vr/openvr/openvr_device.cc
+++ b/device/vr/openvr/openvr_device.cc
@@ -181,7 +181,7 @@
   // If it is the first initialization, OpenVRRenderLoop instance needs to be
   // created and the polling event callback needs to be registered.
   if (!render_loop_) {
-    render_loop_ = base::MakeUnique<OpenVRRenderLoop>(vr_system_);
+    render_loop_ = std::make_unique<OpenVRRenderLoop>(vr_system_);
 
     render_loop_->RegisterPollingEventCallback(base::Bind(
         &OpenVRDevice::OnPollingEvents, weak_ptr_factory_.GetWeakPtr()));
diff --git a/device/vr/openvr/openvr_gamepad_data_fetcher.cc b/device/vr/openvr/openvr_gamepad_data_fetcher.cc
index cccdb372..13ff7b2 100644
--- a/device/vr/openvr/openvr_gamepad_data_fetcher.cc
+++ b/device/vr/openvr/openvr_gamepad_data_fetcher.cc
@@ -46,7 +46,7 @@
 
 std::unique_ptr<GamepadDataFetcher>
 OpenVRGamepadDataFetcher::Factory::CreateDataFetcher() {
-  return base::MakeUnique<OpenVRGamepadDataFetcher>(display_id_, vr_system_);
+  return std::make_unique<OpenVRGamepadDataFetcher>(display_id_, vr_system_);
 }
 
 GamepadSource OpenVRGamepadDataFetcher::Factory::source() {
diff --git a/device/vr/vr_device_manager.cc b/device/vr/vr_device_manager.cc
index d69e266..111760c 100644
--- a/device/vr/vr_device_manager.cc
+++ b/device/vr/vr_device_manager.cc
@@ -29,11 +29,11 @@
 VRDeviceManager::VRDeviceManager() : keep_alive_(false) {
 // Register VRDeviceProviders for the current platform
 #if defined(OS_ANDROID)
-  RegisterProvider(base::MakeUnique<GvrDeviceProvider>());
+  RegisterProvider(std::make_unique<GvrDeviceProvider>());
 #endif
 
 #if BUILDFLAG(ENABLE_OPENVR)
-  RegisterProvider(base::MakeUnique<OpenVRDeviceProvider>());
+  RegisterProvider(std::make_unique<OpenVRDeviceProvider>());
 #endif
 }
 
diff --git a/device/vr/vr_service_impl.cc b/device/vr/vr_service_impl.cc
index 19eaad5..96aa3fac 100644
--- a/device/vr/vr_service_impl.cc
+++ b/device/vr/vr_service_impl.cc
@@ -36,7 +36,7 @@
 void VRServiceImpl::Create(int render_frame_process_id,
                            int render_frame_routing_id,
                            mojom::VRServiceRequest request) {
-  mojo::MakeStrongBinding(base::MakeUnique<VRServiceImpl>(
+  mojo::MakeStrongBinding(std::make_unique<VRServiceImpl>(
                               render_frame_process_id, render_frame_routing_id),
                           std::move(request));
 }
@@ -102,7 +102,7 @@
     // we do mark that we have handled it and verify we haven't changed stacks.
     DCHECK(in_set_client_);
   } else {
-    displays_[device] = base::MakeUnique<VRDisplayImpl>(
+    displays_[device] = std::make_unique<VRDisplayImpl>(
         device, render_frame_process_id_, render_frame_routing_id_,
         client_.get(), std::move(display_info));
     connected_devices_++;
diff --git a/extensions/browser/extension_event_histogram_value.h b/extensions/browser/extension_event_histogram_value.h
index 22e15c44..6b388cec 100644
--- a/extensions/browser/extension_event_histogram_value.h
+++ b/extensions/browser/extension_event_histogram_value.h
@@ -358,7 +358,7 @@
   SCREENLOCK_PRIVATE_ON_CHANGED,
   SCREENLOCK_PRIVATE_ON_AUTH_ATTEMPTED,
   TYPES_CHROME_SETTING_ON_CHANGE,
-  TYPES_PRIVATE_CHROME_DIRECT_SETTING_ON_CHANGE,
+  DELETED_TYPES_PRIVATE_CHROME_DIRECT_SETTING_ON_CHANGE,
   WEB_VIEW_INTERNAL_ON_MESSAGE,
   EXTENSION_VIEW_INTERNAL_ON_LOAD_COMMIT,
   RUNTIME_ON_REQUEST,
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h
index 40115fc4..929df21 100644
--- a/extensions/browser/extension_function_histogram_value.h
+++ b/extensions/browser/extension_function_histogram_value.h
@@ -561,9 +561,9 @@
   DELETED_WEBVIEW_STOP,
   DELETED_WEBVIEW_RELOAD,
   DELETED_WEBVIEW_TERMINATE,
-  TYPES_PRIVATE_CHROMEDIRECTSETTING_GET,
-  TYPES_PRIVATE_CHROMEDIRECTSETTING_SET,
-  TYPES_PRIVATE_CHROMEDIRECTSETTING_CLEAR,
+  DELETED_TYPES_PRIVATE_CHROMEDIRECTSETTING_GET,
+  DELETED_TYPES_PRIVATE_CHROMEDIRECTSETTING_SET,
+  DELETED_TYPES_PRIVATE_CHROMEDIRECTSETTING_CLEAR,
   DELETED_EXPERIMENTAL_SYSTEMINFO_STORAGE_EJECTDEVICE,
   SYSTEM_CPU_GETINFO,
   BOOKMARKMANAGERPRIVATE_REMOVETREES,
diff --git a/extensions/browser/guest_view/web_view/web_view_guest.cc b/extensions/browser/guest_view/web_view/web_view_guest.cc
index 6654820..d2a2122c 100644
--- a/extensions/browser/guest_view/web_view/web_view_guest.cc
+++ b/extensions/browser/guest_view/web_view/web_view_guest.cc
@@ -24,10 +24,6 @@
 #include "content/public/browser/native_web_keyboard_event.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/navigation_handle.h"
-#include "content/public/browser/notification_details.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_source.h"
-#include "content/public/browser/notification_types.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/render_widget_host.h"
@@ -392,14 +388,6 @@
   script_executor_ =
       std::make_unique<ScriptExecutor>(web_contents(), &script_observers_);
 
-  notification_registrar_.Add(this,
-                              content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
-                              content::Source<WebContents>(web_contents()));
-
-  notification_registrar_.Add(this,
-                              content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT,
-                              content::Source<WebContents>(web_contents()));
-
   ExtensionsAPIClient::Get()->AttachWebContentsHelpers(web_contents());
   web_view_permission_helper_ = std::make_unique<WebViewPermissionHelper>(this);
 
@@ -692,33 +680,6 @@
       webview::kEventUnresponsive, std::move(args)));
 }
 
-void WebViewGuest::Observe(int type,
-                           const content::NotificationSource& source,
-                           const content::NotificationDetails& details) {
-  switch (type) {
-    case content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME: {
-      DCHECK_EQ(content::Source<WebContents>(source).ptr(), web_contents());
-      if (content::Source<WebContents>(source).ptr() == web_contents())
-        LoadHandlerCalled();
-      break;
-    }
-    case content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT: {
-      DCHECK_EQ(content::Source<WebContents>(source).ptr(), web_contents());
-      content::ResourceRedirectDetails* resource_redirect_details =
-          content::Details<content::ResourceRedirectDetails>(details).ptr();
-      bool is_top_level = resource_redirect_details->resource_type ==
-                          content::RESOURCE_TYPE_MAIN_FRAME;
-      LoadRedirect(resource_redirect_details->url,
-                   resource_redirect_details->new_url,
-                   is_top_level);
-      break;
-    }
-    default:
-      NOTREACHED() << "Unexpected notification sent.";
-      break;
-  }
-}
-
 void WebViewGuest::StartFind(
     const base::string16& search_text,
     const blink::WebFindOptions& options,
@@ -876,6 +837,12 @@
   find_helper_.CancelAllFindSessions();
 }
 
+void WebViewGuest::DocumentOnLoadCompletedInMainFrame() {
+  auto args = std::make_unique<base::DictionaryValue>();
+  DispatchEventToView(std::make_unique<GuestViewEvent>(
+      webview::kEventContentLoad, std::move(args)));
+}
+
 void WebViewGuest::DidStartNavigation(
     content::NavigationHandle* navigation_handle) {
   // loadStart shouldn't be sent for same document navigations.
@@ -901,6 +868,18 @@
       std::make_unique<GuestViewEvent>(webview::kEventExit, std::move(args)));
 }
 
+void WebViewGuest::DidGetRedirectForResourceRequest(
+    const content::ResourceRedirectDetails& details) {
+  const bool is_top_level =
+      details.resource_type == content::RESOURCE_TYPE_MAIN_FRAME;
+  auto args = std::make_unique<base::DictionaryValue>();
+  args->SetBoolean(guest_view::kIsTopLevel, is_top_level);
+  args->SetString(webview::kNewURL, details.new_url.spec());
+  args->SetString(webview::kOldURL, details.url.spec());
+  DispatchEventToView(std::make_unique<GuestViewEvent>(
+      webview::kEventLoadRedirect, std::move(args)));
+}
+
 void WebViewGuest::UserAgentOverrideSet(const std::string& user_agent) {
   content::NavigationController& controller = web_contents()->GetController();
   content::NavigationEntry* entry = controller.GetVisibleEntry();
@@ -929,23 +908,6 @@
       webview::kEventFrameNameChanged, std::move(args)));
 }
 
-void WebViewGuest::LoadHandlerCalled() {
-  auto args = std::make_unique<base::DictionaryValue>();
-  DispatchEventToView(std::make_unique<GuestViewEvent>(
-      webview::kEventContentLoad, std::move(args)));
-}
-
-void WebViewGuest::LoadRedirect(const GURL& old_url,
-                                const GURL& new_url,
-                                bool is_top_level) {
-  auto args = std::make_unique<base::DictionaryValue>();
-  args->SetBoolean(guest_view::kIsTopLevel, is_top_level);
-  args->SetString(webview::kNewURL, new_url.spec());
-  args->SetString(webview::kOldURL, old_url.spec());
-  DispatchEventToView(std::make_unique<GuestViewEvent>(
-      webview::kEventLoadRedirect, std::move(args)));
-}
-
 void WebViewGuest::PushWebViewStateToIOThread() {
   const GURL& site_url = web_contents()->GetSiteInstance()->GetSiteURL();
   std::string partition_domain;
diff --git a/extensions/browser/guest_view/web_view/web_view_guest.h b/extensions/browser/guest_view/web_view/web_view_guest.h
index 39f3573c..0534fe1 100644
--- a/extensions/browser/guest_view/web_view/web_view_guest.h
+++ b/extensions/browser/guest_view/web_view/web_view_guest.h
@@ -13,8 +13,6 @@
 #include "base/observer_list.h"
 #include "components/guest_view/browser/guest_view.h"
 #include "content/public/browser/javascript_dialog_manager.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
 #include "extensions/browser/guest_view/web_view/javascript_dialog_helper.h"
 #include "extensions/browser/guest_view/web_view/web_view_find_helper.h"
 #include "extensions/browser/guest_view/web_view/web_view_guest_delegate.h"
@@ -36,8 +34,7 @@
 // a particular embedder WebContents. This happens on either initial navigation
 // or through the use of the New Window API, when a new window is attached to
 // a particular <webview>.
-class WebViewGuest : public guest_view::GuestView<WebViewGuest>,
-                     public content::NotificationObserver {
+class WebViewGuest : public guest_view::GuestView<WebViewGuest> {
  public:
   // Clean up state when this GuestView is being destroyed. See
   // GuestViewBase::CleanUp().
@@ -193,11 +190,6 @@
   void WillAttachToEmbedder() final;
   void WillDestroy() final;
 
-  // NotificationObserver implementation.
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) final;
-
   // WebContentsDelegate implementation.
   bool DidAddMessageToConsole(content::WebContents* source,
                               int32_t level,
@@ -259,7 +251,10 @@
   // WebContentsObserver implementation.
   void DidStartNavigation(content::NavigationHandle* navigation_handle) final;
   void DidFinishNavigation(content::NavigationHandle* navigation_handle) final;
+  void DocumentOnLoadCompletedInMainFrame() final;
   void RenderProcessGone(base::TerminationStatus status) final;
+  void DidGetRedirectForResourceRequest(
+      const content::ResourceRedirectDetails& details) final;
   void UserAgentOverrideSet(const std::string& user_agent) final;
   void FrameNameChanged(content::RenderFrameHost* render_frame_host,
                         const std::string& name) final;
@@ -267,14 +262,6 @@
   // Informs the embedder of a frame name change.
   void ReportFrameNameChange(const std::string& name);
 
-  // Called after the load handler is called in the guest's main frame.
-  void LoadHandlerCalled();
-
-  // Called when a redirect notification occurs.
-  void LoadRedirect(const GURL& old_url,
-                    const GURL& new_url,
-                    bool is_top_level);
-
   void PushWebViewStateToIOThread();
   static void RemoveWebViewStateFromIOThread(
       content::WebContents* web_contents);
@@ -321,8 +308,6 @@
   base::ObserverList<ScriptExecutionObserver> script_observers_;
   std::unique_ptr<ScriptExecutor> script_executor_;
 
-  content::NotificationRegistrar notification_registrar_;
-
   // True if the user agent is overridden.
   bool is_overriding_user_agent_;
 
diff --git a/extensions/common/error_utils.cc b/extensions/common/error_utils.cc
index f8f04b7..5fd6d653 100644
--- a/extensions/common/error_utils.cc
+++ b/extensions/common/error_utils.cc
@@ -36,6 +36,19 @@
   return ret_val;
 }
 
+std::string ErrorUtils::FormatErrorMessage(base::StringPiece format,
+                                           base::StringPiece s1,
+                                           base::StringPiece s2,
+                                           base::StringPiece s3,
+                                           base::StringPiece s4) {
+  std::string ret_val = format.as_string();
+  base::ReplaceFirstSubstringAfterOffset(&ret_val, 0, "*", s1);
+  base::ReplaceFirstSubstringAfterOffset(&ret_val, 0, "*", s2);
+  base::ReplaceFirstSubstringAfterOffset(&ret_val, 0, "*", s3);
+  base::ReplaceFirstSubstringAfterOffset(&ret_val, 0, "*", s4);
+  return ret_val;
+}
+
 base::string16 ErrorUtils::FormatErrorMessageUTF16(base::StringPiece format,
                                                    base::StringPiece s1) {
   return base::UTF8ToUTF16(FormatErrorMessage(format, s1));
@@ -54,4 +67,12 @@
   return base::UTF8ToUTF16(FormatErrorMessage(format, s1, s2, s3));
 }
 
+base::string16 ErrorUtils::FormatErrorMessageUTF16(base::StringPiece format,
+                                                   base::StringPiece s1,
+                                                   base::StringPiece s2,
+                                                   base::StringPiece s3,
+                                                   base::StringPiece s4) {
+  return base::UTF8ToUTF16(FormatErrorMessage(format, s1, s2, s3, s4));
+}
+
 }  // namespace extensions
diff --git a/extensions/common/error_utils.h b/extensions/common/error_utils.h
index 5f86ee0b..2575897f 100644
--- a/extensions/common/error_utils.h
+++ b/extensions/common/error_utils.h
@@ -27,6 +27,12 @@
                                         base::StringPiece s2,
                                         base::StringPiece s3);
 
+  static std::string FormatErrorMessage(base::StringPiece format,
+                                        base::StringPiece s1,
+                                        base::StringPiece s2,
+                                        base::StringPiece s3,
+                                        base::StringPiece s4);
+
   static base::string16 FormatErrorMessageUTF16(base::StringPiece format,
                                                 base::StringPiece s1);
 
@@ -38,6 +44,12 @@
                                                 base::StringPiece s1,
                                                 base::StringPiece s2,
                                                 base::StringPiece s3);
+
+  static base::string16 FormatErrorMessageUTF16(base::StringPiece format,
+                                                base::StringPiece s1,
+                                                base::StringPiece s2,
+                                                base::StringPiece s3,
+                                                base::StringPiece s4);
 };
 
 }  // namespace extensions
diff --git a/extensions/renderer/BUILD.gn b/extensions/renderer/BUILD.gn
index 654c8242..2dd37010 100644
--- a/extensions/renderer/BUILD.gn
+++ b/extensions/renderer/BUILD.gn
@@ -90,6 +90,8 @@
     "document_custom_bindings.h",
     "dom_activity_logger.cc",
     "dom_activity_logger.h",
+    "easy_unlock_proximity_required_stub.cc",
+    "easy_unlock_proximity_required_stub.h",
     "event_bindings.cc",
     "event_bindings.h",
     "extension_bindings_system.cc",
diff --git a/extensions/renderer/easy_unlock_proximity_required_stub.cc b/extensions/renderer/easy_unlock_proximity_required_stub.cc
new file mode 100644
index 0000000..89cb44fc8
--- /dev/null
+++ b/extensions/renderer/easy_unlock_proximity_required_stub.cc
@@ -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.
+
+#include "extensions/renderer/easy_unlock_proximity_required_stub.h"
+
+#include "extensions/renderer/bindings/api_event_handler.h"
+#include "gin/arguments.h"
+#include "gin/handle.h"
+#include "gin/object_template_builder.h"
+
+namespace extensions {
+
+v8::Local<v8::Object> EasyUnlockProximityRequiredStub::Create(
+    v8::Isolate* isolate,
+    const std::string& property_name,
+    const base::ListValue* property_values,
+    APIRequestHandler* request_handler,
+    APIEventHandler* event_handler,
+    APITypeReferenceMap* type_refs,
+    const BindingAccessChecker* access_checker) {
+  gin::Handle<EasyUnlockProximityRequiredStub> handle = gin::CreateHandle(
+      isolate, new EasyUnlockProximityRequiredStub(event_handler));
+  return handle.ToV8().As<v8::Object>();
+}
+
+EasyUnlockProximityRequiredStub::EasyUnlockProximityRequiredStub(
+    APIEventHandler* event_handler)
+    : event_handler_(event_handler) {}
+EasyUnlockProximityRequiredStub::~EasyUnlockProximityRequiredStub() {}
+
+gin::WrapperInfo EasyUnlockProximityRequiredStub::kWrapperInfo = {
+    gin::kEmbedderNativeGin};
+
+gin::ObjectTemplateBuilder
+EasyUnlockProximityRequiredStub::GetObjectTemplateBuilder(
+    v8::Isolate* isolate) {
+  return Wrappable<EasyUnlockProximityRequiredStub>::GetObjectTemplateBuilder(
+             isolate)
+      .SetProperty("onChange",
+                   &EasyUnlockProximityRequiredStub::GetOnChangeEvent);
+}
+
+v8::Local<v8::Value> EasyUnlockProximityRequiredStub::GetOnChangeEvent(
+    gin::Arguments* arguments) {
+  v8::Isolate* isolate = arguments->isolate();
+  v8::Local<v8::Context> context = arguments->GetHolderCreationContext();
+  v8::Local<v8::Object> wrapper = GetWrapper(isolate).ToLocalChecked();
+  v8::Local<v8::Private> key = v8::Private::ForApi(
+      isolate, gin::StringToSymbol(isolate, "onChangeEvent"));
+  v8::Local<v8::Value> event;
+  if (!wrapper->GetPrivate(context, key).ToLocal(&event)) {
+    NOTREACHED();
+    return v8::Local<v8::Value>();
+  }
+
+  DCHECK(!event.IsEmpty());
+  if (event->IsUndefined()) {
+    event = event_handler_->CreateAnonymousEventInstance(context);
+    v8::Maybe<bool> set_result = wrapper->SetPrivate(context, key, event);
+    if (!set_result.IsJust() || !set_result.FromJust()) {
+      NOTREACHED();
+      return v8::Local<v8::Value>();
+    }
+  }
+  return event;
+}
+
+}  // namespace extensions
diff --git a/extensions/renderer/easy_unlock_proximity_required_stub.h b/extensions/renderer/easy_unlock_proximity_required_stub.h
new file mode 100644
index 0000000..0d9c6cc
--- /dev/null
+++ b/extensions/renderer/easy_unlock_proximity_required_stub.h
@@ -0,0 +1,66 @@
+// 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_EASY_UNLOCK_PROXIMITY_REQUIRED_STUB_H_
+#define EXTENSIONS_RENDERER_EASY_UNLOCK_PROXIMITY_REQUIRED_STUB_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "extensions/renderer/bindings/argument_spec.h"
+#include "gin/wrappable.h"
+#include "v8/include/v8.h"
+
+namespace base {
+class ListValue;
+}
+
+namespace gin {
+class Arguments;
+}
+
+namespace extensions {
+class APIEventHandler;
+class APIRequestHandler;
+class BindingAccessChecker;
+
+// A stub object for the EasyUnlockProxmityRequired object. This only needs to
+// support a single property, an event for 'onChange' (which will never be
+// triggered).
+// TODO(devlin): Remove this once the preferencesPrivate API is fully removed.
+// https://crbug.com/593166
+class EasyUnlockProximityRequiredStub final
+    : public gin::Wrappable<EasyUnlockProximityRequiredStub> {
+ public:
+  ~EasyUnlockProximityRequiredStub() override;
+
+  static v8::Local<v8::Object> Create(
+      v8::Isolate* isolate,
+      const std::string& property_name,
+      const base::ListValue* property_values,
+      APIRequestHandler* request_handler,
+      APIEventHandler* event_handler,
+      APITypeReferenceMap* type_refs,
+      const BindingAccessChecker* access_checker);
+
+  static gin::WrapperInfo kWrapperInfo;
+
+  gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
+      v8::Isolate* isolate) override;
+
+ private:
+  EasyUnlockProximityRequiredStub(APIEventHandler* event_handler);
+
+  // Returns the onChange event.
+  v8::Local<v8::Value> GetOnChangeEvent(gin::Arguments* arguments);
+
+  // The binding system's event handler; guaranteed to outlive this object.
+  APIEventHandler* const event_handler_;
+
+  DISALLOW_COPY_AND_ASSIGN(EasyUnlockProximityRequiredStub);
+};
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_RENDERER_EASY_UNLOCK_PROXIMITY_REQUIRED_STUB_H_
diff --git a/extensions/renderer/native_extension_bindings_system.cc b/extensions/renderer/native_extension_bindings_system.cc
index 8ef8369d..69b8b958 100644
--- a/extensions/renderer/native_extension_bindings_system.cc
+++ b/extensions/renderer/native_extension_bindings_system.cc
@@ -25,6 +25,7 @@
 #include "extensions/renderer/console.h"
 #include "extensions/renderer/content_setting.h"
 #include "extensions/renderer/declarative_content_hooks_delegate.h"
+#include "extensions/renderer/easy_unlock_proximity_required_stub.h"
 #include "extensions/renderer/extension_frame_helper.h"
 #include "extensions/renderer/ipc_message_sender.h"
 #include "extensions/renderer/module_system.h"
@@ -403,6 +404,9 @@
       weak_factory_(this) {
   api_system_.RegisterCustomType("storage.StorageArea",
                                  base::Bind(&StorageArea::CreateStorageArea));
+  api_system_.RegisterCustomType(
+      "preferencesPrivate.EasyUnlockProximityRequired",
+      base::Bind(&EasyUnlockProximityRequiredStub::Create));
   api_system_.RegisterCustomType("types.ChromeSetting",
                                  base::Bind(&ChromeSetting::Create));
   api_system_.RegisterCustomType(
diff --git a/extensions/renderer/resources/binding.js b/extensions/renderer/resources/binding.js
index 92034552..3b74d1fb 100644
--- a/extensions/renderer/resources/binding.js
+++ b/extensions/renderer/resources/binding.js
@@ -113,9 +113,9 @@
   // This whitelist serves as an extra line of defence to avoid exposing
   // arbitrary extension modules when the |type| definition is poisoned.
   var whitelistedModules = [
-    'ChromeDirectSetting',
     'ChromeSetting',
     'ContentSetting',
+    'EasyUnlockProximityRequired',
     'StorageArea',
   ];
   logging.CHECK($Array.indexOf(whitelistedModules, jsModuleName) !== -1,
diff --git a/extensions/renderer/resources/extension.css b/extensions/renderer/resources/extension.css
index 3fa2d62..a403903 100644
--- a/extensions/renderer/resources/extension.css
+++ b/extensions/renderer/resources/extension.css
@@ -313,7 +313,7 @@
  *
  *   <div class="checkbox">
  *     <label>
- *       <input type="checkbox"></input>
+ *       <input type="checkbox">
  *       <span>
  *     </label>
  *   </div>
diff --git a/gin/public/v8_platform.h b/gin/public/v8_platform.h
index e5760781..b25582c 100644
--- a/gin/public/v8_platform.h
+++ b/gin/public/v8_platform.h
@@ -19,6 +19,7 @@
   static V8Platform* Get();
 
   // v8::Platform implementation.
+  void OnCriticalMemoryPressure() override;
   size_t NumberOfAvailableBackgroundThreads() override;
   void CallOnBackgroundThread(
       v8::Task* task,
diff --git a/gin/v8_platform.cc b/gin/v8_platform.cc
index 1a4f5c3..e9b7b02 100644
--- a/gin/v8_platform.cc
+++ b/gin/v8_platform.cc
@@ -6,6 +6,7 @@
 
 #include <algorithm>
 
+#include "base/allocator/partition_allocator/page_allocator.h"
 #include "base/bind.h"
 #include "base/debug/stack_trace.h"
 #include "base/location.h"
@@ -13,6 +14,7 @@
 #include "base/task_scheduler/post_task.h"
 #include "base/task_scheduler/task_scheduler.h"
 #include "base/trace_event/trace_event.h"
+#include "build/build_config.h"
 #include "gin/per_isolate_data.h"
 
 namespace gin {
@@ -195,6 +197,14 @@
 
 V8Platform::~V8Platform() {}
 
+void V8Platform::OnCriticalMemoryPressure() {
+#if defined(OS_WIN)
+  // Some configurations do not use page_allocator. Only 32 bit Windows systems
+  // reserve memory currently.
+  base::ReleaseReservation();
+#endif
+}
+
 size_t V8Platform::NumberOfAvailableBackgroundThreads() {
   return std::max(1, base::TaskScheduler::GetInstance()
                          ->GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated(
diff --git a/gpu/config/gpu_driver_bug_workarounds.cc b/gpu/config/gpu_driver_bug_workarounds.cc
index bf44f3a..e46a32c 100644
--- a/gpu/config/gpu_driver_bug_workarounds.cc
+++ b/gpu/config/gpu_driver_bug_workarounds.cc
@@ -6,10 +6,7 @@
 
 #include <algorithm>
 
-#include "base/command_line.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_split.h"
-#include "gpu/config/gpu_switches.h"
+#include "base/logging.h"
 
 namespace {
 // Construct GpuDriverBugWorkarounds from a set of enabled workaround IDs.
@@ -44,21 +41,6 @@
     workarounds->max_copy_texture_chromium_size = 262144;
 }
 
-// Process a string of wordaround type IDs (seperated by ',') and set up
-// the corresponding Workaround flags.
-void StringToWorkarounds(const std::string& types,
-                         gpu::GpuDriverBugWorkarounds* workarounds) {
-  std::vector<int32_t> IDs;
-  for (const auto& piece : base::SplitStringPiece(
-           types, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
-    int number = 0;
-    bool succeed = base::StringToInt(piece, &number);
-    DCHECK(succeed);
-    IDs.push_back(number);
-  }
-  IntSetToWorkarounds(IDs, workarounds);
-}
-
 GLint LowerMax(GLint max0, GLint max1) {
   if (max0 > 0 && max1 > 0)
     return std::min(max0, max1);
@@ -79,16 +61,6 @@
 }
 
 GpuDriverBugWorkarounds::GpuDriverBugWorkarounds(
-    const base::CommandLine* command_line) {
-  if (!command_line)
-    return;
-
-  std::string types =
-      command_line->GetSwitchValueASCII(switches::kGpuDriverBugWorkarounds);
-  StringToWorkarounds(types, this);
-}
-
-GpuDriverBugWorkarounds::GpuDriverBugWorkarounds(
     const GpuDriverBugWorkarounds& other) = default;
 
 GpuDriverBugWorkarounds::~GpuDriverBugWorkarounds() {}
diff --git a/gpu/config/gpu_driver_bug_workarounds.h b/gpu/config/gpu_driver_bug_workarounds.h
index 3a4f45d5..18cf6eeea 100644
--- a/gpu/config/gpu_driver_bug_workarounds.h
+++ b/gpu/config/gpu_driver_bug_workarounds.h
@@ -15,17 +15,12 @@
 // Forwardly declare a few GL types to avoid including GL header files.
 typedef int GLint;
 
-namespace base {
-class CommandLine;
-}
-
 namespace gpu {
 
 class GPU_EXPORT GpuDriverBugWorkarounds {
  public:
   GpuDriverBugWorkarounds();
   explicit GpuDriverBugWorkarounds(const std::vector<int32_t>&);
-  explicit GpuDriverBugWorkarounds(const base::CommandLine* command_line);
 
   GpuDriverBugWorkarounds(const GpuDriverBugWorkarounds& other);
 
diff --git a/gpu/ipc/gpu_in_process_thread_service.cc b/gpu/ipc/gpu_in_process_thread_service.cc
index ba6097f..b0da25e5 100644
--- a/gpu/ipc/gpu_in_process_thread_service.cc
+++ b/gpu/ipc/gpu_in_process_thread_service.cc
@@ -15,7 +15,8 @@
     gpu::gles2::MailboxManager* mailbox_manager,
     scoped_refptr<gl::GLShareGroup> share_group,
     const GpuFeatureInfo& gpu_feature_info)
-    : gpu::InProcessCommandBuffer::Service(mailbox_manager,
+    : gpu::InProcessCommandBuffer::Service(GpuPreferences(),
+                                           mailbox_manager,
                                            share_group,
                                            gpu_feature_info),
       task_runner_(task_runner),
diff --git a/gpu/ipc/in_process_command_buffer.cc b/gpu/ipc/in_process_command_buffer.cc
index 5537056..6e251c16 100644
--- a/gpu/ipc/in_process_command_buffer.cc
+++ b/gpu/ipc/in_process_command_buffer.cc
@@ -135,37 +135,6 @@
 
 }  // anonyous namespace
 
-// TODO(zmo): This constructor is used only by DeferredGpuCommandService for
-// Android WebView. We will need to wire up the computed GpuFeatureInfo to
-// here instead of computing from commandline switch..
-InProcessCommandBuffer::Service::Service(const GpuPreferences& gpu_preferences)
-    : Service(gpu_preferences, nullptr, nullptr) {}
-
-InProcessCommandBuffer::Service::Service(
-    gpu::gles2::MailboxManager* mailbox_manager,
-    scoped_refptr<gl::GLShareGroup> share_group,
-    const GpuFeatureInfo& gpu_feature_info)
-    : Service(GpuPreferences(),
-              mailbox_manager,
-              share_group,
-              gpu_feature_info) {}
-
-InProcessCommandBuffer::Service::Service(
-    const GpuPreferences& gpu_preferences,
-    gpu::gles2::MailboxManager* mailbox_manager,
-    scoped_refptr<gl::GLShareGroup> share_group)
-    : gpu_preferences_(gpu_preferences),
-      gpu_driver_bug_workarounds_(base::CommandLine::ForCurrentProcess()),
-      mailbox_manager_(mailbox_manager),
-      share_group_(share_group),
-      shader_translator_cache_(gpu_preferences_) {
-  if (!mailbox_manager_) {
-    // TODO(piman): have embedders own the mailbox manager.
-    owned_mailbox_manager_ = gles2::MailboxManager::Create(gpu_preferences_);
-    mailbox_manager_ = owned_mailbox_manager_.get();
-  }
-}
-
 InProcessCommandBuffer::Service::Service(
     const GpuPreferences& gpu_preferences,
     gpu::gles2::MailboxManager* mailbox_manager,
diff --git a/gpu/ipc/in_process_command_buffer.h b/gpu/ipc/in_process_command_buffer.h
index ef12cf7a..6a808610d 100644
--- a/gpu/ipc/in_process_command_buffer.h
+++ b/gpu/ipc/in_process_command_buffer.h
@@ -196,8 +196,8 @@
   // The serializer interface to the GPU service (i.e. thread).
   class Service {
    public:
-    explicit Service(const gpu::GpuPreferences& gpu_preferences);
-    Service(gles2::MailboxManager* mailbox_manager,
+    Service(const GpuPreferences& gpu_preferences,
+            gles2::MailboxManager* mailbox_manager,
             scoped_refptr<gl::GLShareGroup> share_group,
             const GpuFeatureInfo& gpu_feature_info);
 
@@ -235,14 +235,6 @@
     }
 
    protected:
-    Service(const gpu::GpuPreferences& gpu_preferences,
-            gles2::MailboxManager* mailbox_manager,
-            scoped_refptr<gl::GLShareGroup> share_group,
-            const GpuFeatureInfo& gpu_feature_info);
-    Service(const gpu::GpuPreferences& gpu_preferences,
-            gles2::MailboxManager* mailbox_manager,
-            scoped_refptr<gl::GLShareGroup> share_group);
-
     const GpuPreferences gpu_preferences_;
     const GpuFeatureInfo gpu_feature_info_;
     const GpuDriverBugWorkarounds gpu_driver_bug_workarounds_;
diff --git a/gpu/ipc/service/gpu_init.cc b/gpu/ipc/service/gpu_init.cc
index a7530e5..84188fc 100644
--- a/gpu/ipc/service/gpu_init.cc
+++ b/gpu/ipc/service/gpu_init.cc
@@ -303,6 +303,8 @@
     gpu_info_.sandboxed =
         sandbox_helper_->EnsureSandboxInitialized(watchdog_thread_.get());
   }
+  UMA_HISTOGRAM_BOOLEAN("GPU.Sandbox.InitializedSuccessfully",
+                        gpu_info_.sandboxed);
 
   return true;
 }
diff --git a/ios/chrome/app/application_delegate/url_opener_unittest.mm b/ios/chrome/app/application_delegate/url_opener_unittest.mm
index 1bb857f..253441b 100644
--- a/ios/chrome/app/application_delegate/url_opener_unittest.mm
+++ b/ios/chrome/app/application_delegate/url_opener_unittest.mm
@@ -369,7 +369,7 @@
       id self, NSURL* urlArg, BOOL applicationActive, NSDictionary* options,
       id<TabOpening> tabOpener, id<StartupInformation> startupInformation) {
     hasBeenCalled = YES;
-    EXPECT_EQ([url absoluteString], [urlArg absoluteString]);
+    EXPECT_NSEQ([url absoluteString], [urlArg absoluteString]);
     EXPECT_NSEQ(@"com.apple.mobilesafari",
                 options[UIApplicationOpenURLOptionsSourceApplicationKey]);
     EXPECT_EQ(startupInformationMock, startupInformation);
@@ -481,7 +481,7 @@
       id self, NSURL* urlArg, BOOL applicationActive, NSDictionary* options,
       id<TabOpening> tabOpener, id<StartupInformation> startupInformation) {
     hasBeenCalled = YES;
-    EXPECT_EQ([url absoluteString], [urlArg absoluteString]);
+    EXPECT_NSEQ([url absoluteString], [urlArg absoluteString]);
     EXPECT_NSEQ(@"com.apple.mobilesafari",
                 options[UIApplicationOpenURLOptionsSourceApplicationKey]);
     EXPECT_EQ(startupInformationMock, startupInformation);
diff --git a/ios/chrome/browser/payments/ios_payment_instrument_launcher.h b/ios/chrome/browser/payments/ios_payment_instrument_launcher.h
index bab3a95a..af4eeba 100644
--- a/ios/chrome/browser/payments/ios_payment_instrument_launcher.h
+++ b/ios/chrome/browser/payments/ios_payment_instrument_launcher.h
@@ -18,6 +18,8 @@
 
 namespace payments {
 
+class PaymentDetails;
+
 // Launches a native iOS third party payment app and handles the response
 // returned from that payment app. Only one instance of this object can exist
 // per browser state. This launcher can only handle one request at a time,
@@ -87,12 +89,11 @@
   std::unique_ptr<base::ListValue> SerializeCertificateChain(
       web::NavigationItem* item);
 
-  // Returns the JSON-serialized array of web::PaymentDetailsModifier objects.
+  // Returns the JSON-serialized array of PaymentDetailsModifier objects.
   // |details| is the object that represents the details of a PaymentRequest
-  // object and contains the vector of web::PaymentDetailsModifier objects to
+  // object and contains the vector of PaymentDetailsModifier objects to
   // serialize.
-  std::unique_ptr<base::ListValue> SerializeModifiers(
-      web::PaymentDetails details);
+  std::unique_ptr<base::ListValue> SerializeModifiers(PaymentDetails details);
 
   // Invokes the payment instrument delegate with the appropriate function.
   // If |method_name| or |details| are empty then |delegate_| calls
diff --git a/ios/chrome/browser/payments/ios_payment_instrument_launcher.mm b/ios/chrome/browser/payments/ios_payment_instrument_launcher.mm
index c72d8ec48..54f4e50 100644
--- a/ios/chrome/browser/payments/ios_payment_instrument_launcher.mm
+++ b/ios/chrome/browser/payments/ios_payment_instrument_launcher.mm
@@ -14,6 +14,7 @@
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
+#include "components/payments/core/payment_details.h"
 #include "components/payments/core/payment_instrument.h"
 #include "ios/web/public/navigation_item.h"
 #include "ios/web/public/navigation_manager.h"
@@ -238,7 +239,7 @@
 }
 
 std::unique_ptr<base::ListValue>
-IOSPaymentInstrumentLauncher::SerializeModifiers(web::PaymentDetails details) {
+IOSPaymentInstrumentLauncher::SerializeModifiers(PaymentDetails details) {
   std::unique_ptr<base::ListValue> modifiers =
       base::MakeUnique<base::ListValue>();
   size_t numModifiers = details.modifiers.size();
diff --git a/ios/chrome/browser/payments/payment_request.h b/ios/chrome/browser/payments/payment_request.h
index 9e4ff65..02400d9 100644
--- a/ios/chrome/browser/payments/payment_request.h
+++ b/ios/chrome/browser/payments/payment_request.h
@@ -36,6 +36,8 @@
 class AddressNormalizer;
 class AutofillPaymentInstrument;
 class CurrencyFormatter;
+class PaymentDetails;
+class PaymentShippingOption;
 }  // namespace payments
 
 namespace ios {
@@ -136,7 +138,7 @@
   }
 
   // Returns the payment details from |web_payment_request_|.
-  const web::PaymentDetails& payment_details() const {
+  const PaymentDetails& payment_details() const {
     return web_payment_request_.details;
   }
 
@@ -146,7 +148,7 @@
   // Updates the payment details of the |web_payment_request_|. It also updates
   // the cached references to the shipping options in |web_payment_request_| as
   // well as the reference to the selected shipping option.
-  void UpdatePaymentDetails(const web::PaymentDetails& details);
+  void UpdatePaymentDetails(const PaymentDetails& details);
 
   // PaymentOptionsProvider:
   bool request_shipping() const override;
@@ -254,13 +256,13 @@
   }
 
   // Returns the available shipping options from |web_payment_request_|.
-  const std::vector<web::PaymentShippingOption*>& shipping_options() const {
+  const std::vector<PaymentShippingOption*>& shipping_options() const {
     return shipping_options_;
   }
 
   // Returns the selected shipping option from |web_payment_request_| if there
   // is one. Returns nullptr otherwise.
-  web::PaymentShippingOption* selected_shipping_option() const {
+  PaymentShippingOption* selected_shipping_option() const {
     return selected_shipping_option_;
   }
 
@@ -321,6 +323,10 @@
   // Sets the selected shipping option, if any.
   void SetSelectedShippingOption();
 
+  // Records the number of suggestions shown for contact, shipping and payment
+  // instrument in the JourneyLogger.
+  void RecordNumberOfSuggestionsShown();
+
   // The current state of the payment request.
   State state_;
 
@@ -396,8 +402,8 @@
   std::set<autofill::CreditCard::CardType> supported_card_types_set_;
 
   // A vector of pointers to the shipping options in |web_payment_request_|.
-  std::vector<web::PaymentShippingOption*> shipping_options_;
-  web::PaymentShippingOption* selected_shipping_option_;
+  std::vector<PaymentShippingOption*> shipping_options_;
+  PaymentShippingOption* selected_shipping_option_;
 
   PaymentsProfileComparator profile_comparator_;
 
diff --git a/ios/chrome/browser/payments/payment_request.mm b/ios/chrome/browser/payments/payment_request.mm
index 1e472524..5601854 100644
--- a/ios/chrome/browser/payments/payment_request.mm
+++ b/ios/chrome/browser/payments/payment_request.mm
@@ -20,7 +20,9 @@
 #include "components/payments/core/autofill_payment_instrument.h"
 #include "components/payments/core/currency_formatter.h"
 #include "components/payments/core/features.h"
+#include "components/payments/core/payment_details.h"
 #include "components/payments/core/payment_request_data_util.h"
+#include "components/payments/core/payment_shipping_option.h"
 #include "components/prefs/pref_service.h"
 #include "components/signin/core/browser/signin_manager.h"
 #include "ios/chrome/browser/application_context.h"
@@ -124,6 +126,8 @@
       address_normalizer_.LoadRulesForRegion(countryCode);
     }
   }
+
+  RecordNumberOfSuggestionsShown();
 }
 
 PaymentRequest::~PaymentRequest() {}
@@ -194,7 +198,7 @@
   return browser_state_->GetPrefs();
 }
 
-void PaymentRequest::UpdatePaymentDetails(const web::PaymentDetails& details) {
+void PaymentRequest::UpdatePaymentDetails(const PaymentDetails& details) {
   web_payment_request_.details = details;
   PopulateAvailableShippingOptions();
   SetSelectedShippingOption();
@@ -466,7 +470,7 @@
   std::transform(std::begin(web_payment_request_.details.shipping_options),
                  std::end(web_payment_request_.details.shipping_options),
                  std::back_inserter(shipping_options_),
-                 [](web::PaymentShippingOption& option) { return &option; });
+                 [](PaymentShippingOption& option) { return &option; });
 }
 
 void PaymentRequest::SetSelectedShippingOption() {
@@ -480,4 +484,25 @@
   }
 }
 
+void PaymentRequest::RecordNumberOfSuggestionsShown() {
+  if (request_payer_name() || request_payer_phone() || request_payer_email()) {
+    const bool has_complete_contact = (selected_contact_profile_ != nullptr);
+    journey_logger().SetNumberOfSuggestionsShown(
+        payments::JourneyLogger::Section::SECTION_CONTACT_INFO,
+        contact_profiles().size(), has_complete_contact);
+  }
+
+  if (request_shipping()) {
+    const bool has_complete_shipping = (selected_shipping_profile_ != nullptr);
+    journey_logger().SetNumberOfSuggestionsShown(
+        payments::JourneyLogger::Section::SECTION_SHIPPING_ADDRESS,
+        shipping_profiles().size(), has_complete_shipping);
+  }
+
+  const bool has_complete_instrument = (selected_payment_method_ != nullptr);
+  journey_logger().SetNumberOfSuggestionsShown(
+      payments::JourneyLogger::Section::SECTION_PAYMENT_METHOD,
+      payment_methods().size(), has_complete_instrument);
+}
+
 }  // namespace payments
diff --git a/ios/chrome/browser/payments/payment_request_test_util.mm b/ios/chrome/browser/payments/payment_request_test_util.mm
index c8f31f8d..bd1c44e 100644
--- a/ios/chrome/browser/payments/payment_request_test_util.mm
+++ b/ios/chrome/browser/payments/payment_request_test_util.mm
@@ -5,7 +5,9 @@
 #include "ios/chrome/browser/payments/payment_request_test_util.h"
 
 #include "base/strings/utf_string_conversions.h"
+#include "components/payments/core/payment_item.h"
 #include "components/payments/core/payment_method_data.h"
+#include "components/payments/core/payment_shipping_option.h"
 #include "ios/web/public/payments/payment_request.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -23,19 +25,19 @@
   web_payment_request.details.total.label = base::ASCIIToUTF16("Total");
   web_payment_request.details.total.amount.value = base::ASCIIToUTF16("1.00");
   web_payment_request.details.total.amount.currency = base::ASCIIToUTF16("USD");
-  web::PaymentItem display_item;
+  payments::PaymentItem display_item;
   display_item.label = base::ASCIIToUTF16("Subtotal");
   display_item.amount.value = base::ASCIIToUTF16("1.00");
   display_item.amount.currency = base::ASCIIToUTF16("USD");
   web_payment_request.details.display_items.push_back(display_item);
-  web::PaymentShippingOption shipping_option;
+  payments::PaymentShippingOption shipping_option;
   shipping_option.id = base::ASCIIToUTF16("123456");
   shipping_option.label = base::ASCIIToUTF16("1-Day");
   shipping_option.amount.value = base::ASCIIToUTF16("0.99");
   shipping_option.amount.currency = base::ASCIIToUTF16("USD");
   shipping_option.selected = true;
   web_payment_request.details.shipping_options.push_back(shipping_option);
-  web::PaymentShippingOption shipping_option2;
+  payments::PaymentShippingOption shipping_option2;
   shipping_option2.id = base::ASCIIToUTF16("654321");
   shipping_option2.label = base::ASCIIToUTF16("10-Days");
   shipping_option2.amount.value = base::ASCIIToUTF16("0.01");
diff --git a/ios/chrome/browser/payments/payment_request_unittest.mm b/ios/chrome/browser/payments/payment_request_unittest.mm
index 38206f4..70c89863 100644
--- a/ios/chrome/browser/payments/payment_request_unittest.mm
+++ b/ios/chrome/browser/payments/payment_request_unittest.mm
@@ -16,7 +16,9 @@
 #include "components/payments/core/autofill_payment_instrument.h"
 #include "components/payments/core/currency_formatter.h"
 #include "components/payments/core/features.h"
+#include "components/payments/core/payment_details.h"
 #include "components/payments/core/payment_method_data.h"
+#include "components/payments/core/payment_shipping_option.h"
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
 #include "ios/chrome/browser/payments/payment_request_test_util.h"
@@ -53,10 +55,10 @@
       : chrome_browser_state_(TestChromeBrowserState::Builder().Build()) {}
 
   // Returns PaymentDetails with one shipping option that's selected.
-  web::PaymentDetails CreateDetailsWithShippingOption() {
-    web::PaymentDetails details;
-    std::vector<web::PaymentShippingOption> shipping_options;
-    web::PaymentShippingOption option1;
+  PaymentDetails CreateDetailsWithShippingOption() {
+    PaymentDetails details;
+    std::vector<PaymentShippingOption> shipping_options;
+    PaymentShippingOption option1;
     option1.id = base::UTF8ToUTF16("option:1");
     option1.selected = true;
     shipping_options.push_back(std::move(option1));
@@ -373,17 +375,17 @@
   web::PaymentRequest web_payment_request;
   autofill::TestPersonalDataManager personal_data_manager;
 
-  web::PaymentDetails details;
-  std::vector<web::PaymentShippingOption> shipping_options;
-  web::PaymentShippingOption option1;
+  PaymentDetails details;
+  std::vector<PaymentShippingOption> shipping_options;
+  PaymentShippingOption option1;
   option1.id = base::UTF8ToUTF16("option:1");
   option1.selected = false;
   shipping_options.push_back(std::move(option1));
-  web::PaymentShippingOption option2;
+  PaymentShippingOption option2;
   option2.id = base::UTF8ToUTF16("option:2");
   option2.selected = true;
   shipping_options.push_back(std::move(option2));
-  web::PaymentShippingOption option3;
+  PaymentShippingOption option3;
   option3.id = base::UTF8ToUTF16("option:3");
   option3.selected = true;
   shipping_options.push_back(std::move(option3));
@@ -399,7 +401,7 @@
 
   // Simulate an update that no longer has any shipping options. There is no
   // longer a selected shipping option.
-  web::PaymentDetails new_details;
+  PaymentDetails new_details;
   payment_request.UpdatePaymentDetails(std::move(new_details));
   EXPECT_EQ(nullptr, payment_request.selected_shipping_option());
 }
@@ -457,7 +459,7 @@
 
   web::PaymentRequest web_payment_request;
   // No shipping options.
-  web_payment_request.details = web::PaymentDetails();
+  web_payment_request.details = PaymentDetails();
   web_payment_request.options = CreatePaymentOptions(
       /*request_payer_name=*/true, /*request_payer_phone=*/true,
       /*request_payer_email=*/true, /*request_shipping=*/true);
diff --git a/ios/chrome/browser/payments/payment_response_helper.mm b/ios/chrome/browser/payments/payment_response_helper.mm
index 4801802..5d267bd 100644
--- a/ios/chrome/browser/payments/payment_response_helper.mm
+++ b/ios/chrome/browser/payments/payment_response_helper.mm
@@ -12,6 +12,7 @@
 #include "components/payments/core/address_normalization_manager.h"
 #include "components/payments/core/journey_logger.h"
 #include "components/payments/core/payment_request_data_util.h"
+#include "components/payments/core/payment_shipping_option.h"
 #include "ios/chrome/browser/payments/payment_request.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -76,7 +77,7 @@
         data_util::GetPaymentAddressFromAutofillProfile(
             shipping_address_, payment_request_->GetApplicationLocale()));
 
-    web::PaymentShippingOption* shippingOption =
+    PaymentShippingOption* shippingOption =
         payment_request_->selected_shipping_option();
     DCHECK(shippingOption);
     response.shipping_option = shippingOption->id;
diff --git a/ios/chrome/browser/payments/test_payment_request.h b/ios/chrome/browser/payments/test_payment_request.h
index b9d92fb..0d4f539 100644
--- a/ios/chrome/browser/payments/test_payment_request.h
+++ b/ios/chrome/browser/payments/test_payment_request.h
@@ -20,12 +20,12 @@
 }  // namespace ios
 
 namespace payments {
+class PaymentShippingOption;
 class PaymentsProfileComparator;
 }  // namespace payments
 
 namespace web {
 class PaymentRequest;
-class PaymentShippingOption;
 class WebState;
 }  // namespace web
 
@@ -96,7 +96,7 @@
   void ResetParsedPaymentMethodData();
 
   // Sets the currently selected shipping option for this PaymentRequest flow.
-  void set_selected_shipping_option(web::PaymentShippingOption* option) {
+  void set_selected_shipping_option(payments::PaymentShippingOption* option) {
     selected_shipping_option_ = option;
   }
 
diff --git a/ios/chrome/browser/ui/authentication/BUILD.gn b/ios/chrome/browser/ui/authentication/BUILD.gn
index 37034c1..ec9bc7d3 100644
--- a/ios/chrome/browser/ui/authentication/BUILD.gn
+++ b/ios/chrome/browser/ui/authentication/BUILD.gn
@@ -179,17 +179,3 @@
   ]
   libs = [ "XCTest.framework" ]
 }
-
-source_set("eg_test_support") {
-  configs += [ "//build/config/compiler:enable_arc" ]
-  testonly = true
-  sources = [
-    "signin_promo_view_earlgrey_utils.h",
-    "signin_promo_view_earlgrey_utils.mm",
-  ]
-  deps = [
-    ":authentication_ui",
-    "//ios/chrome/test/earl_grey:test_support",
-    "//ios/third_party/earl_grey",
-  ]
-}
diff --git a/ios/chrome/browser/ui/authentication/signin_promo_view_earlgrey_utils.h b/ios/chrome/browser/ui/authentication/signin_promo_view_earlgrey_utils.h
deleted file mode 100644
index da7f9a7..0000000
--- a/ios/chrome/browser/ui/authentication/signin_promo_view_earlgrey_utils.h
+++ /dev/null
@@ -1,20 +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 IOS_CHROME_BROWSER_UI_AUTHENTICATION_SIGN_PROMO_VIEW_EARLGREY_UTILS_H_
-#define IOS_CHROME_BROWSER_UI_AUTHENTICATION_SIGN_PROMO_VIEW_EARLGREY_UTILS_H_
-
-#import "ios/chrome/browser/ui/authentication/signin_promo_view.h"
-
-@interface SignPromoViewEarlgreyUtils : NSObject
-
-// Checks that the sign-in promo view is visible using the right mode.
-+ (void)checkSigninPromoVisibleWithMode:(SigninPromoViewMode)mode;
-
-// Checks that the sign-in promo view is not visible.
-+ (void)checkSigninPromoNotVisible;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_AUTHENTICATION_SIGN_PROMO_VIEW_EARLGREY_UTILS_H_
diff --git a/ios/chrome/browser/ui/authentication/signin_promo_view_earlgrey_utils.mm b/ios/chrome/browser/ui/authentication/signin_promo_view_earlgrey_utils.mm
deleted file mode 100644
index a19fb1ca..0000000
--- a/ios/chrome/browser/ui/authentication/signin_promo_view_earlgrey_utils.mm
+++ /dev/null
@@ -1,62 +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 "ios/chrome/browser/ui/authentication/signin_promo_view_earlgrey_utils.h"
-
-#import <EarlGrey/EarlGrey.h>
-
-#import "ios/chrome/test/earl_grey/chrome_matchers.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-using chrome_test_util::PrimarySignInButton;
-using chrome_test_util::SecondarySignInButton;
-
-@implementation SignPromoViewEarlgreyUtils
-
-+ (void)checkSigninPromoVisibleWithMode:(SigninPromoViewMode)mode {
-  [[EarlGrey
-      selectElementWithMatcher:grey_allOf(
-                                   grey_accessibilityID(kSigninPromoViewId),
-                                   grey_sufficientlyVisible(), nil)]
-      assertWithMatcher:grey_notNil()];
-  [[EarlGrey
-      selectElementWithMatcher:grey_allOf(PrimarySignInButton(),
-                                          grey_sufficientlyVisible(), nil)]
-      assertWithMatcher:grey_notNil()];
-  switch (mode) {
-    case SigninPromoViewModeColdState:
-      [[EarlGrey
-          selectElementWithMatcher:grey_allOf(SecondarySignInButton(),
-                                              grey_sufficientlyVisible(), nil)]
-          assertWithMatcher:grey_nil()];
-      break;
-    case SigninPromoViewModeWarmState:
-      [[EarlGrey
-          selectElementWithMatcher:grey_allOf(SecondarySignInButton(),
-                                              grey_sufficientlyVisible(), nil)]
-          assertWithMatcher:grey_notNil()];
-      break;
-  }
-}
-
-+ (void)checkSigninPromoNotVisible {
-  [[EarlGrey
-      selectElementWithMatcher:grey_allOf(
-                                   grey_accessibilityID(kSigninPromoViewId),
-                                   grey_sufficientlyVisible(), nil)]
-      assertWithMatcher:grey_nil()];
-  [[EarlGrey
-      selectElementWithMatcher:grey_allOf(PrimarySignInButton(),
-                                          grey_sufficientlyVisible(), nil)]
-      assertWithMatcher:grey_nil()];
-  [[EarlGrey
-      selectElementWithMatcher:grey_allOf(SecondarySignInButton(),
-                                          grey_sufficientlyVisible(), nil)]
-      assertWithMatcher:grey_nil()];
-}
-
-@end
diff --git a/ios/chrome/browser/ui/bookmarks/BUILD.gn b/ios/chrome/browser/ui/bookmarks/BUILD.gn
index 45d3f4cb..861f6c8 100644
--- a/ios/chrome/browser/ui/bookmarks/BUILD.gn
+++ b/ios/chrome/browser/ui/bookmarks/BUILD.gn
@@ -195,7 +195,6 @@
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/ui",
     "//ios/chrome/browser/ui/authentication:authentication_ui",
-    "//ios/chrome/browser/ui/authentication:eg_test_support",
     "//ios/chrome/browser/ui/commands",
     "//ios/chrome/browser/ui/toolbar",
     "//ios/chrome/browser/ui/tools_menu",
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
index be0bbfb..6c56fd0 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
@@ -193,7 +193,6 @@
                                          style:UIBarButtonItemStyleDone
                                         target:self
                                         action:@selector(navigationBarCancel:)];
-    doneButton.accessibilityIdentifier = @"DONE";
     self.navigationItem.rightBarButtonItem = doneButton;
     self.navigationItem.backBarButtonItem =
         [[UIBarButtonItem alloc] initWithTitle:@""
diff --git a/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm b/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm
index 0922794d..bea273e 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm
@@ -20,7 +20,6 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/pref_names.h"
 #import "ios/chrome/browser/ui/authentication/signin_promo_view.h"
-#import "ios/chrome/browser/ui/authentication/signin_promo_view_earlgrey_utils.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/toolbar/toolbar_controller.h"
@@ -1052,10 +1051,10 @@
   [self setTearDownHandler:^{
     [BookmarksTestCase setPromoAlreadySeen:NO];
   }];
-  // Check that sign-in promo view is visible.
+  // Check that promo is visible.
   [BookmarksTestCase verifyPromoAlreadySeen:NO];
-  [SignPromoViewEarlgreyUtils
-      checkSigninPromoVisibleWithMode:SigninPromoViewModeColdState];
+  [[EarlGrey selectElementWithMatcher:PrimarySignInButton()]
+      assertWithMatcher:grey_sufficientlyVisible()];
 
   // Tap the dismiss button.
   [[EarlGrey
@@ -1063,96 +1062,39 @@
       performAction:grey_tap()];
 
   // Wait until promo is gone.
-  [SignPromoViewEarlgreyUtils checkSigninPromoNotVisible];
+  [[EarlGrey selectElementWithMatcher:SecondarySignInButton()]
+      assertWithMatcher:grey_notVisible()];
 
   // Check that the promo already seen state is updated.
   [BookmarksTestCase verifyPromoAlreadySeen:YES];
 }
 
-// Tests the tapping on the primary button of sign-in promo view in a cold
-// state makes the sign-in sheet appear, and the promo still appears after
-// dismissing the sheet.
-- (void)testSignInPromoWithColdStateUsingPrimaryButton {
-  [BookmarksTestCase openBookmarks];
-
-  // Check that sign-in promo view are visible.
-  [BookmarksTestCase verifyPromoAlreadySeen:NO];
-  [SignPromoViewEarlgreyUtils
-      checkSigninPromoVisibleWithMode:SigninPromoViewModeColdState];
-
-  // Tap the primary button.
-  [[EarlGrey
-      selectElementWithMatcher:grey_allOf(PrimarySignInButton(),
-                                          grey_sufficientlyVisible(), nil)]
-      performAction:grey_tap()];
-  [[EarlGrey selectElementWithMatcher:grey_buttonTitle(@"Cancel")]
-      performAction:grey_tap()];
-
-  // Check that the bookmarks UI reappeared and the cell is still here.
-  [BookmarksTestCase verifyPromoAlreadySeen:NO];
-  [SignPromoViewEarlgreyUtils
-      checkSigninPromoVisibleWithMode:SigninPromoViewModeColdState];
-}
-
-// Tests the tapping on the primary button of sign-in promo view in a warm
-// state makes the confirmaiton sheet appear, and the promo still appears after
-// dismissing the sheet.
-- (void)testSignInPromoWithWarmStateUsingPrimaryButton {
+// Tests that tapping Sign in on the promo make the Sign in sheet appear and
+// the promo still appears after dismissing the Sign in sheet.
+- (void)testUIPromoSignIn {
   [BookmarksTestCase setupStandardBookmarks];
   [BookmarksTestCase openTopLevelBookmarksFolder];
 
   // Set up a fake identity.
   ChromeIdentity* identity =
-      [FakeChromeIdentity identityWithEmail:@"fakefoo@gmail.com"
-                                     gaiaID:@"fakefoopassword"
-                                       name:@"Fake Foo"];
-  ios::FakeChromeIdentityService::GetInstanceFromChromeProvider()->AddIdentity(
-      identity);
-
-  // Check that sign-in promo view are visible.
-  [BookmarksTestCase verifyPromoAlreadySeen:NO];
-  [SignPromoViewEarlgreyUtils
-      checkSigninPromoVisibleWithMode:SigninPromoViewModeWarmState];
-
-  // Tap the secondary button.
-  [[EarlGrey
-      selectElementWithMatcher:grey_allOf(PrimarySignInButton(),
-                                          grey_sufficientlyVisible(), nil)]
-      performAction:grey_tap()];
-
-  // Tap the UNDO button.
-  [[EarlGrey selectElementWithMatcher:grey_buttonTitle(@"UNDO")]
-      performAction:grey_tap()];
-
-  // Check that the bookmarks UI reappeared and the cell is still here.
-  [BookmarksTestCase verifyPromoAlreadySeen:NO];
-  [SignPromoViewEarlgreyUtils
-      checkSigninPromoVisibleWithMode:SigninPromoViewModeWarmState];
-}
-
-// Tests the tapping on the secondary button of sign-in promo view in a warm
-// state makes the sign-in sheet appear, and the promo still appears after
-// dismissing the sheet.
-- (void)testSignInPromoWithWarmStateUsingSecondaryButton {
-  [BookmarksTestCase setupStandardBookmarks];
-  [BookmarksTestCase openTopLevelBookmarksFolder];
-  // Set up a fake identity.
-  ChromeIdentity* identity =
       [FakeChromeIdentity identityWithEmail:@"fakefoo@egmail.com"
                                      gaiaID:@"fakefoopassword"
                                        name:@"Fake Foo"];
   ios::FakeChromeIdentityService::GetInstanceFromChromeProvider()->AddIdentity(
       identity);
 
-  // Check that sign-in promo view are visible.
+  // Check that promo is visible.
   [BookmarksTestCase verifyPromoAlreadySeen:NO];
-  [SignPromoViewEarlgreyUtils
-      checkSigninPromoVisibleWithMode:SigninPromoViewModeWarmState];
-
-  // Tap the secondary button.
   [[EarlGrey
       selectElementWithMatcher:grey_allOf(SecondarySignInButton(),
                                           grey_sufficientlyVisible(), nil)]
+      assertWithMatcher:grey_notNil()];
+
+  // Tap the Sign in button.
+  [[EarlGrey
+      selectElementWithMatcher:grey_allOf(grey_accessibilityID(
+                                              kSigninPromoSecondaryButtonId),
+                                          grey_sufficientlyVisible(), nil)]
       performAction:grey_tap()];
 
   // Tap the CANCEL button.
@@ -1162,38 +1104,12 @@
                      uppercaseString])] performAction:grey_tap()];
 
   // Check that the bookmarks UI reappeared and the cell is still here.
-  [BookmarksTestCase verifyPromoAlreadySeen:NO];
-  [SignPromoViewEarlgreyUtils
-      checkSigninPromoVisibleWithMode:SigninPromoViewModeWarmState];
-}
+  [[EarlGrey
+      selectElementWithMatcher:grey_allOf(SecondarySignInButton(),
+                                          grey_sufficientlyVisible(), nil)]
+      assertWithMatcher:grey_notNil()];
 
-// Tests that the sign-in promo should not be shown after been shown 19 times.
-- (void)testAutomaticSigninPromoDismiss {
-  ios::ChromeBrowserState* browser_state =
-      chrome_test_util::GetOriginalBrowserState();
-  PrefService* prefs = browser_state->GetPrefs();
-  prefs->SetInteger(prefs::kIosBookmarkSigninPromoDisplayedCount, 19);
-  [BookmarksTestCase openBookmarks];
-  // Check the sign-in promo view is visible.
-  [SignPromoViewEarlgreyUtils
-      checkSigninPromoVisibleWithMode:SigninPromoViewModeColdState];
-  // Check the sign-in promo will not be shown anymore.
-  [BookmarksTestCase verifyPromoAlreadySeen:YES];
-  GREYAssertEqual(
-      20, prefs->GetInteger(prefs::kIosBookmarkSigninPromoDisplayedCount),
-      @"Should have incremented the display count");
-  // Close the bookmark view and open it again.
-  if (IsCompact()) {
-    [[EarlGrey selectElementWithMatcher:BookmarksDoneButton()]
-        performAction:grey_tap()];
-    [BookmarksTestCase openBookmarks];
-  } else {
-    [BookmarksTestCase closeAllTabs];
-    chrome_test_util::OpenNewTab();
-  }
-  [[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
-  // Check that the sign-in promo is not visible anymore.
-  [SignPromoViewEarlgreyUtils checkSigninPromoNotVisible];
+  [BookmarksTestCase verifyPromoAlreadySeen:NO];
 }
 
 // Tests that all elements on the bookmarks landing page are accessible.
diff --git a/ios/chrome/browser/ui/bookmarks/bookmarks_new_generation_egtest.mm b/ios/chrome/browser/ui/bookmarks/bookmarks_new_generation_egtest.mm
index 910da23..0c00147 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmarks_new_generation_egtest.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmarks_new_generation_egtest.mm
@@ -17,7 +17,6 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/pref_names.h"
 #import "ios/chrome/browser/ui/authentication/signin_promo_view.h"
-#import "ios/chrome/browser/ui/authentication/signin_promo_view_earlgrey_utils.h"
 #include "ios/chrome/browser/ui/tools_menu/tools_menu_constants.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
@@ -54,12 +53,6 @@
   return ButtonWithAccessibilityLabel(@"Back");
 }
 
-// Matcher for the Back button on the bookmarks UI.
-id<GREYMatcher> BookmarksDoneButton() {
-  return grey_allOf(grey_accessibilityID(@"DONE"), grey_sufficientlyVisible(),
-                    nil);
-}
-
 // Bookmark integration tests for Chrome.
 @interface BookmarksNewGenTestCase : ChromeTestCase
 @end
@@ -167,16 +160,17 @@
   [self setTearDownHandler:^{
     [BookmarksNewGenTestCase setPromoAlreadySeen:NO];
   }];
-  // Check that sign-in promo view is visible.
+  // Check that promo is visible.
   [BookmarksNewGenTestCase verifyPromoAlreadySeen:NO];
-  [SignPromoViewEarlgreyUtils
-      checkSigninPromoVisibleWithMode:SigninPromoViewModeColdState];
+  [[EarlGrey selectElementWithMatcher:PrimarySignInButton()]
+      assertWithMatcher:grey_sufficientlyVisible()];
 
   // Go to child node.
   [BookmarksNewGenTestCase openMobileBookmarks];
 
   // Wait until promo is gone.
-  [SignPromoViewEarlgreyUtils checkSigninPromoNotVisible];
+  [[EarlGrey selectElementWithMatcher:SecondarySignInButton()]
+      assertWithMatcher:grey_notVisible()];
 
   // Check that the promo already seen state is not updated.
   [BookmarksNewGenTestCase verifyPromoAlreadySeen:NO];
@@ -207,10 +201,10 @@
   [self setTearDownHandler:^{
     [BookmarksNewGenTestCase setPromoAlreadySeen:NO];
   }];
-  // Check that sign-in promo view is visible.
+  // Check that promo is visible.
   [BookmarksNewGenTestCase verifyPromoAlreadySeen:NO];
-  [SignPromoViewEarlgreyUtils
-      checkSigninPromoVisibleWithMode:SigninPromoViewModeColdState];
+  [[EarlGrey selectElementWithMatcher:PrimarySignInButton()]
+      assertWithMatcher:grey_sufficientlyVisible()];
 
   // Tap the dismiss button.
   [[EarlGrey
@@ -218,48 +212,16 @@
       performAction:grey_tap()];
 
   // Wait until promo is gone.
-  [SignPromoViewEarlgreyUtils checkSigninPromoNotVisible];
+  [[EarlGrey selectElementWithMatcher:SecondarySignInButton()]
+      assertWithMatcher:grey_notVisible()];
 
   // Check that the promo already seen state is updated.
   [BookmarksNewGenTestCase verifyPromoAlreadySeen:YES];
 }
 
-// Tests the tapping on the primary button of sign-in promo view in a cold
-// state makes the sign-in sheet appear, and the promo still appears after
-// dismissing the sheet.
-- (void)testSignInPromoWithColdStateUsingPrimaryButton {
-  if (IsIPadIdiom()) {
-    EARL_GREY_TEST_DISABLED(@"Test disabled on iPad.");
-  }
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(
-      bookmark_new_generation::features::kBookmarkNewGeneration);
-
-  [BookmarksNewGenTestCase openBookmarks];
-
-  // Check that sign-in promo view are visible.
-  [BookmarksNewGenTestCase verifyPromoAlreadySeen:NO];
-  [SignPromoViewEarlgreyUtils
-      checkSigninPromoVisibleWithMode:SigninPromoViewModeColdState];
-
-  // Tap the primary button.
-  [[EarlGrey
-      selectElementWithMatcher:grey_allOf(PrimarySignInButton(),
-                                          grey_sufficientlyVisible(), nil)]
-      performAction:grey_tap()];
-  [[EarlGrey selectElementWithMatcher:grey_buttonTitle(@"Cancel")]
-      performAction:grey_tap()];
-
-  // Check that the bookmarks UI reappeared and the cell is still here.
-  [BookmarksNewGenTestCase verifyPromoAlreadySeen:NO];
-  [SignPromoViewEarlgreyUtils
-      checkSigninPromoVisibleWithMode:SigninPromoViewModeColdState];
-}
-
-// Tests the tapping on the primary button of sign-in promo view in a warm
-// state makes the confirmaiton sheet appear, and the promo still appears after
-// dismissing the sheet.
-- (void)testSignInPromoWithWarmStateUsingPrimaryButton {
+// Tests that tapping Sign in on the promo make the Sign in sheet appear and
+// the promo still appears after dismissing the Sign in sheet.
+- (void)testUIPromoSignIn {
   if (IsIPadIdiom()) {
     EARL_GREY_TEST_DISABLED(@"Test disabled on iPad.");
   }
@@ -272,7 +234,7 @@
 
   // Set up a fake identity.
   ChromeIdentity* identity =
-      [FakeChromeIdentity identityWithEmail:@"fakefoo@gmail.com"
+      [FakeChromeIdentity identityWithEmail:@"fakefoo@egmail.com"
                                      gaiaID:@"fakefoopassword"
                                        name:@"Fake Foo"];
   ios::FakeChromeIdentityService::GetInstanceFromChromeProvider()->AddIdentity(
@@ -307,81 +269,6 @@
   [BookmarksNewGenTestCase verifyPromoAlreadySeen:NO];
 }
 
-// Tests the tapping on the secondary button of sign-in promo view in a warm
-// state makes the sign-in sheet appear, and the promo still appears after
-// dismissing the sheet.
-- (void)testSignInPromoWithWarmStateUsingSecondaryButton {
-  if (IsIPadIdiom()) {
-    EARL_GREY_TEST_DISABLED(@"Test disabled on iPad.");
-  }
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(
-      bookmark_new_generation::features::kBookmarkNewGeneration);
-
-  [BookmarksNewGenTestCase setupStandardBookmarks];
-  [BookmarksNewGenTestCase openBookmarks];
-  // Set up a fake identity.
-  ChromeIdentity* identity =
-      [FakeChromeIdentity identityWithEmail:@"fakefoo@egmail.com"
-                                     gaiaID:@"fakefoopassword"
-                                       name:@"Fake Foo"];
-  ios::FakeChromeIdentityService::GetInstanceFromChromeProvider()->AddIdentity(
-      identity);
-
-  // Check that sign-in promo view are visible.
-  [BookmarksNewGenTestCase verifyPromoAlreadySeen:NO];
-  [SignPromoViewEarlgreyUtils
-      checkSigninPromoVisibleWithMode:SigninPromoViewModeWarmState];
-
-  // Tap the secondary button.
-  [[EarlGrey
-      selectElementWithMatcher:grey_allOf(SecondarySignInButton(),
-                                          grey_sufficientlyVisible(), nil)]
-      performAction:grey_tap()];
-
-  // Tap the CANCEL button.
-  [[EarlGrey selectElementWithMatcher:
-                 grey_buttonTitle([l10n_util::GetNSString(
-                     IDS_IOS_ACCOUNT_CONSISTENCY_SETUP_SKIP_BUTTON)
-                     uppercaseString])] performAction:grey_tap()];
-
-  // Check that the bookmarks UI reappeared and the cell is still here.
-  [BookmarksNewGenTestCase verifyPromoAlreadySeen:NO];
-  [SignPromoViewEarlgreyUtils
-      checkSigninPromoVisibleWithMode:SigninPromoViewModeWarmState];
-}
-
-// Tests that the sign-in promo should not be shown after been shown 19 times.
-- (void)testAutomaticSigninPromoDismiss {
-  if (IsIPadIdiom()) {
-    EARL_GREY_TEST_DISABLED(@"Test disabled on iPad.");
-  }
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(
-      bookmark_new_generation::features::kBookmarkNewGeneration);
-
-  ios::ChromeBrowserState* browser_state =
-      chrome_test_util::GetOriginalBrowserState();
-  PrefService* prefs = browser_state->GetPrefs();
-  prefs->SetInteger(prefs::kIosBookmarkSigninPromoDisplayedCount, 19);
-  [BookmarksNewGenTestCase openBookmarks];
-  // Check the sign-in promo view is visible.
-  [SignPromoViewEarlgreyUtils
-      checkSigninPromoVisibleWithMode:SigninPromoViewModeColdState];
-  // Check the sign-in promo will not be shown anymore.
-  [BookmarksNewGenTestCase verifyPromoAlreadySeen:YES];
-  GREYAssertEqual(
-      20, prefs->GetInteger(prefs::kIosBookmarkSigninPromoDisplayedCount),
-      @"Should have incremented the display count");
-  // Close the bookmark view and open it again.
-  [[EarlGrey selectElementWithMatcher:BookmarksDoneButton()]
-      performAction:grey_tap()];
-  [BookmarksNewGenTestCase openBookmarks];
-  [[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
-  // Check that the sign-in promo is not visible anymore.
-  [SignPromoViewEarlgreyUtils checkSigninPromoNotVisible];
-}
-
 #pragma mark - Helpers
 
 // Navigates to the bookmark manager UI.
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm
index 77b713c9..158c20f 100644
--- a/ios/chrome/browser/ui/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -520,7 +520,7 @@
   id<AppRatingPrompt> _rateThisAppDialog;
 
   // Native controller vended to tab before Tab is added to the tab model.
-  id _temporaryNativeController;
+  __weak id _temporaryNativeController;
 
   // Notifies the toolbar menu of reading list changes.
   ReadingListMenuNotifier* _readingListMenuNotifier;
@@ -721,15 +721,9 @@
 // promotion.
 - (void)presentNewIncognitoTabTipBubble;
 
-// Create and show the find bar.
-- (void)initFindBarForTab;
-// Search for find bar query string.
-- (void)searchFindInPage;
 // Update find bar with model data. If |shouldFocus| is set to YES, the text
 // field will become first responder.
 - (void)updateFindBar:(BOOL)initialUpdate shouldFocus:(BOOL)shouldFocus;
-// Close and disable find in page bar.
-- (void)closeFindInPage;
 // Hide find bar.
 - (void)hideFindBarWithAnimation:(BOOL)animate;
 // Shows find bar. If |selectText| is YES, all text inside the Find Bar
@@ -4348,6 +4342,71 @@
   [_rateThisAppDialog show];
 }
 
+- (void)showFindInPage {
+  if (!self.canShowFindBar)
+    return;
+
+  if (!_findBarController) {
+    _findBarController =
+        [[FindBarControllerIOS alloc] initWithIncognito:_isOffTheRecord];
+    _findBarController.dispatcher = self.dispatcher;
+  }
+
+  Tab* tab = [_model currentTab];
+  DCHECK(tab);
+  auto* helper = FindTabHelper::FromWebState(tab.webState);
+  DCHECK(!helper->IsFindUIActive());
+  helper->SetFindUIActive(true);
+  [self showFindBarWithAnimation:YES selectText:YES shouldFocus:YES];
+}
+
+- (void)closeFindInPage {
+  __weak BrowserViewController* weakSelf = self;
+  Tab* currentTab = [_model currentTab];
+  if (currentTab) {
+    FindTabHelper::FromWebState(currentTab.webState)->StopFinding(^{
+      [weakSelf updateFindBar:NO shouldFocus:NO];
+    });
+  }
+}
+
+- (void)searchFindInPage {
+  DCHECK([_model currentTab]);
+  auto* helper = FindTabHelper::FromWebState([_model currentTab].webState);
+  __weak BrowserViewController* weakSelf = self;
+  helper->StartFinding(
+      [_findBarController searchTerm], ^(FindInPageModel* model) {
+        BrowserViewController* strongSelf = weakSelf;
+        if (!strongSelf) {
+          return;
+        }
+        [strongSelf->_findBarController updateResultsCount:model];
+      });
+
+  if (!_isOffTheRecord)
+    helper->PersistSearchTerm();
+}
+
+- (void)findNextStringInPage {
+  Tab* currentTab = [_model currentTab];
+  DCHECK(currentTab);
+  // TODO(crbug.com/603524): Reshow find bar if necessary.
+  FindTabHelper::FromWebState(currentTab.webState)
+      ->ContinueFinding(FindTabHelper::FORWARD, ^(FindInPageModel* model) {
+        [_findBarController updateResultsCount:model];
+      });
+}
+
+- (void)findPreviousStringInPage {
+  Tab* currentTab = [_model currentTab];
+  DCHECK(currentTab);
+  // TODO(crbug.com/603524): Reshow find bar if necessary.
+  FindTabHelper::FromWebState(currentTab.webState)
+      ->ContinueFinding(FindTabHelper::REVERSE, ^(FindInPageModel* model) {
+        [_findBarController updateResultsCount:model];
+      });
+}
+
 #pragma mark - Command Handling
 
 - (IBAction)chromeExecuteCommand:(id)sender {
@@ -4355,36 +4414,8 @@
 
   if (!_model || !_browserState)
     return;
-  Tab* currentTab = [_model currentTab];
 
   switch (command) {
-    case IDC_FIND:
-      [self initFindBarForTab];
-      break;
-    case IDC_FIND_NEXT: {
-      DCHECK(currentTab);
-      // TODO(crbug.com/603524): Reshow find bar if necessary.
-      FindTabHelper::FromWebState(currentTab.webState)
-          ->ContinueFinding(FindTabHelper::FORWARD, ^(FindInPageModel* model) {
-            [_findBarController updateResultsCount:model];
-          });
-      break;
-    }
-    case IDC_FIND_PREVIOUS: {
-      DCHECK(currentTab);
-      // TODO(crbug.com/603524): Reshow find bar if necessary.
-      FindTabHelper::FromWebState(currentTab.webState)
-          ->ContinueFinding(FindTabHelper::REVERSE, ^(FindInPageModel* model) {
-            [_findBarController updateResultsCount:model];
-          });
-      break;
-    }
-    case IDC_FIND_CLOSE:
-      [self closeFindInPage];
-      break;
-    case IDC_FIND_UPDATE:
-      [self searchFindInPage];
-      break;
     case IDC_HELP_PAGE_VIA_MENU:
       [self showHelpPage];
       break;
@@ -4563,50 +4594,6 @@
   [self updateFindBar:YES shouldFocus:shouldFocus];
 }
 
-// Create find bar controller and pass it to the web controller.
-- (void)initFindBarForTab {
-  if (!self.canShowFindBar)
-    return;
-
-  if (!_findBarController)
-    _findBarController =
-        [[FindBarControllerIOS alloc] initWithIncognito:_isOffTheRecord];
-
-  Tab* tab = [_model currentTab];
-  DCHECK(tab);
-  auto* helper = FindTabHelper::FromWebState(tab.webState);
-  DCHECK(!helper->IsFindUIActive());
-  helper->SetFindUIActive(true);
-  [self showFindBarWithAnimation:YES selectText:YES shouldFocus:YES];
-}
-
-- (void)searchFindInPage {
-  DCHECK([_model currentTab]);
-  auto* helper = FindTabHelper::FromWebState([_model currentTab].webState);
-  __weak BrowserViewController* weakSelf = self;
-  helper->StartFinding(
-      [_findBarController searchTerm], ^(FindInPageModel* model) {
-        BrowserViewController* strongSelf = weakSelf;
-        if (!strongSelf) {
-          return;
-        }
-        [strongSelf->_findBarController updateResultsCount:model];
-      });
-
-  if (!_isOffTheRecord)
-    helper->PersistSearchTerm();
-}
-
-- (void)closeFindInPage {
-  __weak BrowserViewController* weakSelf = self;
-  Tab* currentTab = [_model currentTab];
-  if (currentTab) {
-    FindTabHelper::FromWebState(currentTab.webState)->StopFinding(^{
-      [weakSelf updateFindBar:NO shouldFocus:NO];
-    });
-  }
-}
-
 - (void)updateFindBar:(BOOL)initialUpdate shouldFocus:(BOOL)shouldFocus {
   // TODO(crbug.com/731045): This early return temporarily replaces a DCHECK.
   // For unknown reasons, this DCHECK sometimes was hit in the wild, resulting
diff --git a/ios/chrome/browser/ui/commands/browser_commands.h b/ios/chrome/browser/ui/commands/browser_commands.h
index 00172fb..7eacd16 100644
--- a/ios/chrome/browser/ui/commands/browser_commands.h
+++ b/ios/chrome/browser/ui/commands/browser_commands.h
@@ -71,6 +71,22 @@
 // Shows the "rate this app" dialog.
 - (void)showRateThisAppDialog;
 
+// Shows the Find In Page bar.
+- (void)showFindInPage;
+
+// Close and disable Find In Page bar.
+- (void)closeFindInPage;
+
+// Search the current tab for the query string in the Find In Page bar.
+- (void)searchFindInPage;
+
+// Go to the next location of the Find In Page query string in the current tab.
+- (void)findNextStringInPage;
+
+// Go to the previous location of the Find In Page query string in the current
+// tab.
+- (void)findPreviousStringInPage;
+
 @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 eb196f8..162a342 100644
--- a/ios/chrome/browser/ui/commands/ios_command_ids.h
+++ b/ios/chrome/browser/ui/commands/ios_command_ids.h
@@ -13,14 +13,9 @@
 // also need to be updated.
 
 // clang-format off
-#define IDC_FIND                                       37000
-#define IDC_FIND_NEXT                                  37001
-#define IDC_FIND_PREVIOUS                              37002
 #define IDC_SHOW_BOOKMARK_MANAGER                      40011
 #define IDC_HELP_PAGE_VIA_MENU                         40020
 #define IDC_SHOW_SIGNIN_IOS                            40905
-#define IDC_FIND_CLOSE                                 40907
-#define IDC_FIND_UPDATE                                40908
 #define IDC_SHOW_ADD_ACCOUNT                           40910
 #define IDC_SHOW_PAGE_INFO                             40911
 #define IDC_HIDE_PAGE_INFO                             40912
diff --git a/ios/chrome/browser/ui/find_bar/find_bar_controller_ios.h b/ios/chrome/browser/ui/find_bar/find_bar_controller_ios.h
index 6a93f00..0549ea1 100644
--- a/ios/chrome/browser/ui/find_bar/find_bar_controller_ios.h
+++ b/ios/chrome/browser/ui/find_bar/find_bar_controller_ios.h
@@ -7,6 +7,7 @@
 
 #import <UIKit/UIKit.h>
 
+@protocol BrowserCommands;
 @class FindInPageModel;
 
 // The a11y ID of the find-in-page bar.
@@ -17,6 +18,9 @@
 // The main view, for both iPhone or iPad.
 @property(nonatomic, readonly, strong) IBOutlet UIView* view;
 
+// The dispatcher for sending browser commands.
+@property(nonatomic, weak) id<BrowserCommands> dispatcher;
+
 // Init with incognito style.
 - (instancetype)initWithIncognito:(BOOL)isIncognito;
 // Current input search term.
diff --git a/ios/chrome/browser/ui/find_bar/find_bar_controller_ios.mm b/ios/chrome/browser/ui/find_bar/find_bar_controller_ios.mm
index 12ac2edf..09f9084 100644
--- a/ios/chrome/browser/ui/find_bar/find_bar_controller_ios.mm
+++ b/ios/chrome/browser/ui/find_bar/find_bar_controller_ios.mm
@@ -14,7 +14,7 @@
 #import "ios/chrome/browser/find_in_page/find_in_page_controller.h"
 #import "ios/chrome/browser/find_in_page/find_in_page_model.h"
 #import "ios/chrome/browser/ui/UIView+SizeClassSupport.h"
-#import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
+#import "ios/chrome/browser/ui/commands/browser_commands.h"
 #import "ios/chrome/browser/ui/find_bar/find_bar_view.h"
 #include "ios/chrome/browser/ui/ui_util.h"
 #include "ui/base/l10n/l10n_util_mac.h"
@@ -67,10 +67,9 @@
 // Returns the appropriate variant of the image for |image_name| based on
 // |_isIncognito| and device idiom.
 - (UIImage*)imageWithName:(NSString*)image_name;
-// Delay searching for the first |kSearchDelayChars| characters of a search term
-// to give time for a user to type out a longer word.  Short words are currently
-// very inefficient and lock up the UIWebView.
-- (void)editingChanged:(id)sender;
+// Responds to touches that make editing changes on the text field, triggering
+// find-in-page searches for the field's current value.
+- (void)editingChanged;
 // Return the expected find bar height. This will include the status bar height
 // when running iOS7 on an iPhone.
 - (CGFloat)findBarHeight;
@@ -97,6 +96,7 @@
 @synthesize findBarView = _findBarView;
 @synthesize delayTimer = _delayTimer;
 @synthesize isIncognito = _isIncognito;
+@synthesize dispatcher = _dispatcher;
 
 #pragma mark - Lifecycle
 
@@ -128,6 +128,7 @@
 
   self.findBarView = [[FindBarView alloc]
       initWithDarkAppearance:self.isIncognito && !IsIPadIdiom()];
+  self.findBarView.dispatcher = self.dispatcher;
   [findBarBackground addSubview:self.findBarView];
   self.findBarView.translatesAutoresizingMaskIntoConstraints = NO;
   NSMutableArray* constraints = [[NSMutableArray alloc] init];
@@ -154,7 +155,7 @@
 
   self.findBarView.inputField.delegate = self;
   [self.findBarView.inputField addTarget:self
-                                  action:@selector(editingChanged:)
+                                  action:@selector(editingChanged)
                         forControlEvents:UIControlEventEditingChanged];
   [self.findBarView.nextButton addTarget:self
                                   action:@selector(hideKeyboard:)
@@ -231,7 +232,7 @@
   if (initialUpdate) {
     // Set initial text and first search.
     [self.findBarView.inputField setText:model.text];
-    [self editingChanged:self.findBarView.inputField];
+    [self editingChanged];
   }
 
   // Focus input field if necessary.
@@ -423,24 +424,23 @@
       }];
 }
 
-- (void)textChanged {
-  [self.view chromeExecuteCommand:self.findBarView.inputField];
-}
-
-- (void)editingChanged:(id)sender {
+- (void)editingChanged {
   [self.delayTimer invalidate];
   NSUInteger length = [[self searchTerm] length];
-  if (length == 0)
-    return [self textChanged];
+  if (length == 0) {
+    [self.dispatcher searchFindInPage];
+    return;
+  }
 
-  // Delay delivery of text change event.  Use a longer delay when the input
-  // length is short.
+  // Delay delivery of the search text event to give time for a user to type out
+  // a longer word.  Use a longer delay when the input length is short, as short
+  // words are currently very inefficient and lock up the web view.
   NSTimeInterval delay =
       (length > kSearchDelayChars) ? kSearchShortDelay : kSearchLongDelay;
   self.delayTimer =
       [NSTimer scheduledTimerWithTimeInterval:delay
-                                       target:self
-                                     selector:@selector(textChanged)
+                                       target:self.dispatcher
+                                     selector:@selector(searchFindInPage)
                                      userInfo:nil
                                       repeats:NO];
 }
diff --git a/ios/chrome/browser/ui/find_bar/find_bar_view.h b/ios/chrome/browser/ui/find_bar/find_bar_view.h
index 1382d40..83d78b2b5 100644
--- a/ios/chrome/browser/ui/find_bar/find_bar_view.h
+++ b/ios/chrome/browser/ui/find_bar/find_bar_view.h
@@ -7,6 +7,8 @@
 
 #import <UIKit/UIKit.h>
 
+@protocol BrowserCommands;
+
 // The a11y ID of the text input field in the find-in-page bar.
 extern NSString* const kFindInPageInputFieldId;
 
@@ -45,6 +47,8 @@
 @property(nonatomic, weak) UIButton* nextButton;
 // Button to dismiss Find in Page.
 @property(nonatomic, weak) UIButton* closeButton;
+// Dispatcher for sending browser commands.
+@property(nonatomic, weak) id<BrowserCommands> dispatcher;
 
 @end
 
diff --git a/ios/chrome/browser/ui/find_bar/find_bar_view.mm b/ios/chrome/browser/ui/find_bar/find_bar_view.mm
index c31f076c..21f576a 100644
--- a/ios/chrome/browser/ui/find_bar/find_bar_view.mm
+++ b/ios/chrome/browser/ui/find_bar/find_bar_view.mm
@@ -5,8 +5,7 @@
 #import "ios/chrome/browser/ui/find_bar/find_bar_view.h"
 
 #include "components/strings/grit/components_strings.h"
-#import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
-#import "ios/chrome/browser/ui/commands/ios_command_ids.h"
+#import "ios/chrome/browser/ui/commands/browser_commands.h"
 #import "ios/chrome/browser/ui/find_bar/find_bar_touch_forwarding_view.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
@@ -45,6 +44,7 @@
 @synthesize nextButton = _nextButton;
 @synthesize closeButton = _closeButton;
 @synthesize separator = _separator;
+@synthesize dispatcher = _dispatcher;
 
 - (instancetype)initWithDarkAppearance:(BOOL)darkAppearance {
   self = [super initWithFrame:CGRectZero];
@@ -72,7 +72,6 @@
       [[UITextField alloc] initWithFrame:CGRectZero];
   self.inputField = inputFieldScoped;
   self.inputField.backgroundColor = [UIColor clearColor];
-  self.inputField.tag = IDC_FIND_UPDATE;
   self.inputField.translatesAutoresizingMaskIntoConstraints = NO;
   self.inputField.placeholder =
       l10n_util::GetNSString(IDS_IOS_PLACEHOLDER_FIND_IN_PAGE);
@@ -154,7 +153,6 @@
   ]];
   self.previousButton.isAccessibilityElement = YES;
   self.previousButton.accessibilityTraits = UIAccessibilityTraitButton;
-  self.previousButton.tag = IDC_FIND_PREVIOUS;
   self.previousButton.translatesAutoresizingMaskIntoConstraints = NO;
 
   // Next button with an arrow.
@@ -168,7 +166,6 @@
     [self.nextButton.leadingAnchor
         constraintEqualToAnchor:self.previousButton.trailingAnchor],
   ]];
-  self.nextButton.tag = IDC_FIND_NEXT;
   self.nextButton.translatesAutoresizingMaskIntoConstraints = NO;
 
   // Close button with a cross.
@@ -184,18 +181,17 @@
     [self.closeButton.leadingAnchor
         constraintEqualToAnchor:self.nextButton.trailingAnchor],
   ]];
-  self.closeButton.tag = IDC_FIND_CLOSE;
   self.closeButton.translatesAutoresizingMaskIntoConstraints = NO;
 
-  // Connect outlets.
-  [self.nextButton addTarget:self
-                      action:@selector(chromeExecuteCommand:)
+  // Connect dispatcher.
+  [self.nextButton addTarget:self.dispatcher
+                      action:@selector(findNextStringInPage)
             forControlEvents:UIControlEventTouchUpInside];
-  [self.previousButton addTarget:self
-                          action:@selector(chromeExecuteCommand:)
+  [self.previousButton addTarget:self.dispatcher
+                          action:@selector(findPreviousStringInPage)
                 forControlEvents:UIControlEventTouchUpInside];
-  [self.closeButton addTarget:self
-                       action:@selector(chromeExecuteCommand:)
+  [self.closeButton addTarget:self.dispatcher
+                       action:@selector(closeFindInPage)
              forControlEvents:UIControlEventTouchUpInside];
 
   // A11y labels.
diff --git a/ios/chrome/browser/ui/key_commands_provider.mm b/ios/chrome/browser/ui/key_commands_provider.mm
index 5455d256..69a1272 100644
--- a/ios/chrome/browser/ui/key_commands_provider.mm
+++ b/ios/chrome/browser/ui/key_commands_provider.mm
@@ -140,20 +140,20 @@
                                      title:l10n_util::GetNSStringWithFixup(
                                                IDS_IOS_TOOLS_MENU_FIND_IN_PAGE)
                                     action:^{
-                                      execute(IDC_FIND);
+                                      [weakDispatcher showFindInPage];
                                     }],
       [UIKeyCommand cr_keyCommandWithInput:@"g"
                              modifierFlags:UIKeyModifierCommand
                                      title:nil
                                     action:^{
-                                      execute(IDC_FIND_NEXT);
+                                      [weakDispatcher findNextStringInPage];
                                     }],
       [UIKeyCommand
           cr_keyCommandWithInput:@"g"
                    modifierFlags:UIKeyModifierCommand | UIKeyModifierShift
                            title:nil
                           action:^{
-                            execute(IDC_FIND_PREVIOUS);
+                            [weakDispatcher findPreviousStringInPage];
                           }],
       [UIKeyCommand cr_keyCommandWithInput:@"r"
                              modifierFlags:UIKeyModifierCommand
diff --git a/ios/chrome/browser/ui/payments/BUILD.gn b/ios/chrome/browser/ui/payments/BUILD.gn
index 007738a..668f6efe 100644
--- a/ios/chrome/browser/ui/payments/BUILD.gn
+++ b/ios/chrome/browser/ui/payments/BUILD.gn
@@ -230,6 +230,7 @@
     "payment_request_debit_egtest.mm",
     "payment_request_egtest_base.h",
     "payment_request_egtest_base.mm",
+    "payment_request_journey_logger_egtest.mm",
     "payment_request_misc_egtest.mm",
     "payment_request_payment_app_egtest.mm",
     "payment_request_payment_method_identifier_egtest.mm",
diff --git a/ios/chrome/browser/ui/payments/js_payment_request_manager.h b/ios/chrome/browser/ui/payments/js_payment_request_manager.h
index 597ef38..15ca6d1 100644
--- a/ios/chrome/browser/ui/payments/js_payment_request_manager.h
+++ b/ios/chrome/browser/ui/payments/js_payment_request_manager.h
@@ -10,12 +10,12 @@
 #import "ios/web/public/web_state/js/crw_js_injection_manager.h"
 
 namespace payments {
+class PaymentShippingOption;
 struct PaymentAddress;
 }  // namespace payments
 
 namespace web {
 class PaymentResponse;
-class PaymentShippingOption;
 }  // namespace web
 
 // Injects the JavaScript that implements the Payment Request API and provides
@@ -88,7 +88,8 @@
 
 // Updates the shippingOption property on the PaymentRequest object and
 // dispatches a shippingoptionchange event.
-- (void)updateShippingOption:(const web::PaymentShippingOption&)shippingOption
+- (void)updateShippingOption:
+            (const payments::PaymentShippingOption&)shippingOption
            completionHandler:(ProceduralBlockWithBool)completionHanlder;
 
 @end
diff --git a/ios/chrome/browser/ui/payments/js_payment_request_manager.mm b/ios/chrome/browser/ui/payments/js_payment_request_manager.mm
index 59927aa..180cad9 100644
--- a/ios/chrome/browser/ui/payments/js_payment_request_manager.mm
+++ b/ios/chrome/browser/ui/payments/js_payment_request_manager.mm
@@ -10,6 +10,7 @@
 #include "base/strings/sys_string_conversions.h"
 #include "base/values.h"
 #include "components/payments/core/payment_address.h"
+#include "components/payments/core/payment_shipping_option.h"
 #include "ios/web/public/payments/payment_request.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -137,7 +138,8 @@
   [self executeScript:script completionHandler:completionHanlder];
 }
 
-- (void)updateShippingOption:(const web::PaymentShippingOption&)shippingOption
+- (void)updateShippingOption:
+            (const payments::PaymentShippingOption&)shippingOption
            completionHandler:(ProceduralBlockWithBool)completionHanlder {
   NSString* script =
       [NSString stringWithFormat:
diff --git a/ios/chrome/browser/ui/payments/payment_items_display_mediator.mm b/ios/chrome/browser/ui/payments/payment_items_display_mediator.mm
index adc3d9aa..e9095dbe 100644
--- a/ios/chrome/browser/ui/payments/payment_items_display_mediator.mm
+++ b/ios/chrome/browser/ui/payments/payment_items_display_mediator.mm
@@ -10,6 +10,7 @@
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/payments/core/currency_formatter.h"
+#include "components/payments/core/payment_item.h"
 #include "components/strings/grit/components_strings.h"
 #include "ios/chrome/browser/payments/payment_request.h"
 #import "ios/chrome/browser/ui/payments/cells/price_item.h"
@@ -68,7 +69,7 @@
 }
 
 - (NSArray<CollectionViewItem*>*)lineItems {
-  const std::vector<web::PaymentItem>& paymentItems =
+  const std::vector<payments::PaymentItem>& paymentItems =
       _paymentRequest->payment_details().display_items;
   NSMutableArray<CollectionViewItem*>* lineItems =
       [NSMutableArray arrayWithCapacity:paymentItems.size()];
diff --git a/ios/chrome/browser/ui/payments/payment_request_coordinator.h b/ios/chrome/browser/ui/payments/payment_request_coordinator.h
index 6b57f1f..2066fda 100644
--- a/ios/chrome/browser/ui/payments/payment_request_coordinator.h
+++ b/ios/chrome/browser/ui/payments/payment_request_coordinator.h
@@ -31,13 +31,10 @@
 }  // namespace ios
 
 namespace payments {
-class PaymentRequest;
-}  // namespace payments
-
-namespace web {
 class PaymentDetails;
+class PaymentRequest;
 class PaymentShippingOption;
-}  // namespace web
+}  // namespace payments
 
 @class PaymentRequestCoordinator;
 
@@ -65,7 +62,7 @@
 // Notifies the delegate that the user has selected a shipping option.
 - (void)paymentRequestCoordinator:(PaymentRequestCoordinator*)coordinator
           didSelectShippingOption:
-              (const web::PaymentShippingOption&)shippingOption;
+              (const payments::PaymentShippingOption&)shippingOption;
 
 @end
 
@@ -134,7 +131,7 @@
                resultDelegate;
 
 // Updates the payment details of the PaymentRequest and updates the UI.
-- (void)updatePaymentDetails:(web::PaymentDetails)paymentDetails;
+- (void)updatePaymentDetails:(payments::PaymentDetails)paymentDetails;
 
 // Displays an error message. Invokes |callback| when the message is dismissed.
 - (void)displayErrorWithCallback:(ProceduralBlock)callback;
diff --git a/ios/chrome/browser/ui/payments/payment_request_coordinator.mm b/ios/chrome/browser/ui/payments/payment_request_coordinator.mm
index ae3f2dce..41087458 100644
--- a/ios/chrome/browser/ui/payments/payment_request_coordinator.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_coordinator.mm
@@ -10,8 +10,10 @@
 #include "components/autofill/core/browser/credit_card.h"
 #include "components/payments/core/autofill_payment_instrument.h"
 #include "components/payments/core/payment_address.h"
+#include "components/payments/core/payment_details.h"
 #include "components/payments/core/payment_instrument.h"
 #include "components/payments/core/payment_request_data_util.h"
+#include "components/payments/core/payment_shipping_option.h"
 #include "components/strings/grit/components_strings.h"
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/payments/payment_request.h"
@@ -152,7 +154,7 @@
   _fullCardRequester->GetFullCard(card, _autofillManager, resultDelegate);
 }
 
-- (void)updatePaymentDetails:(web::PaymentDetails)paymentDetails {
+- (void)updatePaymentDetails:(payments::PaymentDetails)paymentDetails {
   [_updatePaymentSummaryItemTimer invalidate];
 
   BOOL totalValueChanged =
@@ -424,7 +426,7 @@
 - (void)shippingOptionSelectionCoordinator:
             (ShippingOptionSelectionCoordinator*)coordinator
                    didSelectShippingOption:
-                       (web::PaymentShippingOption*)shippingOption {
+                       (payments::PaymentShippingOption*)shippingOption {
   DCHECK(shippingOption);
   [_delegate paymentRequestCoordinator:self
                didSelectShippingOption:*shippingOption];
diff --git a/ios/chrome/browser/ui/payments/payment_request_coordinator_unittest.mm b/ios/chrome/browser/ui/payments/payment_request_coordinator_unittest.mm
index c2a740e..4b53b950 100644
--- a/ios/chrome/browser/ui/payments/payment_request_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_coordinator_unittest.mm
@@ -16,6 +16,7 @@
 #include "components/payments/core/payment_address.h"
 #include "components/payments/core/payment_instrument.h"
 #include "components/payments/core/payment_request_data_util.h"
+#include "components/payments/core/payment_shipping_option.h"
 #include "components/payments/core/payments_test_util.h"
 #include "ios/chrome/browser/payments/payment_request_test_util.h"
 #import "ios/chrome/browser/ui/payments/payment_request_unittest_base.h"
@@ -43,7 +44,7 @@
     const autofill::AutofillProfile&);
 typedef void (^mock_coordinator_select_shipping_option)(
     PaymentRequestCoordinator*,
-    const web::PaymentShippingOption&);
+    const payments::PaymentShippingOption&);
 
 - (void)paymentRequestCoordinatorDidConfirm:
     (PaymentRequestCoordinator*)coordinator {
@@ -66,7 +67,7 @@
 
 - (void)paymentRequestCoordinator:(PaymentRequestCoordinator*)coordinator
           didSelectShippingOption:
-              (const web::PaymentShippingOption&)shippingOption {
+              (const payments::PaymentShippingOption&)shippingOption {
   return static_cast<mock_coordinator_select_shipping_option>(
       [self blockForSelector:_cmd])(coordinator, shippingOption);
 }
@@ -169,7 +170,7 @@
       initWithBaseViewController:base_view_controller];
   [coordinator setPaymentRequest:payment_request()];
 
-  web::PaymentShippingOption shipping_option;
+  payments::PaymentShippingOption shipping_option;
   shipping_option.id = base::ASCIIToUTF16("123456");
   shipping_option.label = base::ASCIIToUTF16("1-Day");
   shipping_option.amount.value = base::ASCIIToUTF16("0.99");
@@ -181,13 +182,13 @@
   id delegate_mock([[PaymentRequestCoordinatorDelegateMock alloc]
       initWithRepresentedObject:delegate]);
   SEL selector = @selector(paymentRequestCoordinator:didSelectShippingOption:);
-  [delegate_mock
-                onSelector:selector
-      callBlockExpectation:^(PaymentRequestCoordinator* callerCoordinator,
-                             const web::PaymentShippingOption& shippingOption) {
-        EXPECT_EQ(shipping_option, shippingOption);
-        EXPECT_EQ(coordinator, callerCoordinator);
-      }];
+  [delegate_mock onSelector:selector
+       callBlockExpectation:^(
+           PaymentRequestCoordinator* callerCoordinator,
+           const payments::PaymentShippingOption& shippingOption) {
+         EXPECT_EQ(shipping_option, shippingOption);
+         EXPECT_EQ(coordinator, callerCoordinator);
+       }];
   [coordinator setDelegate:delegate_mock];
 
   // Call the ShippingOptionSelectionCoordinator delegate method.
diff --git a/ios/chrome/browser/ui/payments/payment_request_egtest_base.h b/ios/chrome/browser/ui/payments/payment_request_egtest_base.h
index 368243d..36109a7 100644
--- a/ios/chrome/browser/ui/payments/payment_request_egtest_base.h
+++ b/ios/chrome/browser/ui/payments/payment_request_egtest_base.h
@@ -43,6 +43,14 @@
 // Returns the instance of PersonalDataManager for current ChromeBrowserState.
 - (autofill::PersonalDataManager*)personalDataManager;
 
+// Loads the specified |page|, which should be the name of a file in the
+// //components/test/data/payments directory.
+- (void)loadTestPage:(const std::string&)page;
+
+// Taps the 'PAY' button in the UI, enters the specified |cvc| and confirms
+// payment.
+- (void)payWithCreditCardUsingCVC:(NSString*)cvc;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_PAYMENTS_PAYMENT_REQUEST_EGTEST_BASE_H_
diff --git a/ios/chrome/browser/ui/payments/payment_request_egtest_base.mm b/ios/chrome/browser/ui/payments/payment_request_egtest_base.mm
index 2c8315a..ce3934b9 100644
--- a/ios/chrome/browser/ui/payments/payment_request_egtest_base.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_egtest_base.mm
@@ -10,16 +10,20 @@
 #include "base/feature_list.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
+#include "base/strings/stringprintf.h"
 #include "base/strings/sys_string_conversions.h"
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/credit_card.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/payments/core/features.h"
+#include "components/strings/grit/components_strings.h"
 #include "ios/chrome/browser/autofill/personal_data_manager_factory.h"
 #include "ios/chrome/browser/payments/ios_payment_request_cache_factory.h"
 #import "ios/chrome/test/app/chrome_test_util.h"
 #import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
+#import "ios/chrome/test/earl_grey/chrome_matchers.h"
 #import "ios/testing/wait_util.h"
+#import "ios/web/public/test/http_server/http_server.h"
 #import "ios/web/public/test/web_view_interaction_test_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -123,4 +127,25 @@
       chrome_test_util::GetOriginalBrowserState());
 }
 
+- (void)loadTestPage:(const std::string&)page {
+  std::string fullPath = base::StringPrintf(
+      "https://components/test/data/payments/%s", page.c_str());
+  [ChromeEarlGrey loadURL:web::test::HttpServer::MakeUrl(fullPath)];
+}
+
+- (void)payWithCreditCardUsingCVC:(NSString*)cvc {
+  [[EarlGrey
+      selectElementWithMatcher:chrome_test_util::ButtonWithAccessibilityLabelId(
+                                   IDS_PAYMENTS_PAY_BUTTON)]
+      performAction:grey_tap()];
+
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"CVC_textField")]
+      performAction:grey_replaceText(cvc)];
+
+  [[EarlGrey
+      selectElementWithMatcher:chrome_test_util::ButtonWithAccessibilityLabelId(
+                                   IDS_AUTOFILL_CARD_UNMASK_CONFIRM_BUTTON)]
+      performAction:grey_tap()];
+}
+
 @end
diff --git a/ios/chrome/browser/ui/payments/payment_request_journey_logger_egtest.mm b/ios/chrome/browser/ui/payments/payment_request_journey_logger_egtest.mm
new file mode 100644
index 0000000..563efc7
--- /dev/null
+++ b/ios/chrome/browser/ui/payments/payment_request_journey_logger_egtest.mm
@@ -0,0 +1,95 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/histogram_tester.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/payments/core/journey_logger.h"
+#include "components/strings/grit/components_strings.h"
+#import "ios/chrome/browser/ui/payments/payment_request_egtest_base.h"
+#import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+using payments::JourneyLogger;
+}  // namespace
+
+// Journey logger tests for Payment Request.
+@interface PaymentRequestJourneyLoggerEGTest : PaymentRequestEGTestBase
+@end
+
+@implementation PaymentRequestJourneyLoggerEGTest {
+  autofill::AutofillProfile _profile;
+  autofill::CreditCard _creditCard1;
+}
+
+#pragma mark - XCTestCase
+
+// Set up called once before each test.
+- (void)setUp {
+  [super setUp];
+
+  _profile = autofill::test::GetFullProfile();
+  [self addAutofillProfile:_profile];
+
+  _creditCard1 = autofill::test::GetCreditCard();
+  _creditCard1.set_billing_address_id(_profile.guid());
+  [self addCreditCard:_creditCard1];
+}
+
+#pragma mark - Tests
+
+// Tests that the selected instrument metric is correctly logged when the
+// Payment Request is completed with a credit card.
+- (void)testSelectedPaymentMethod {
+  base::HistogramTester histogramTester;
+
+  [self loadTestPage:"payment_request_no_shipping_test.html"];
+  [ChromeEarlGrey tapWebViewElementWithID:@"buy"];
+  [self payWithCreditCardUsingCVC:@"123"];
+
+  // Make sure the correct events were logged.
+  std::vector<base::Bucket> buckets =
+      histogramTester.GetAllSamples("PaymentRequest.Events");
+  GREYAssertEqual(1U, buckets.size(), @"Only one bucket");
+  GREYAssertTrue(buckets[0].min & JourneyLogger::EVENT_SHOWN, @"");
+  GREYAssertTrue(buckets[0].min & JourneyLogger::EVENT_PAY_CLICKED, @"");
+  GREYAssertTrue(
+      buckets[0].min & JourneyLogger::EVENT_RECEIVED_INSTRUMENT_DETAILS, @"");
+  GREYAssertFalse(buckets[0].min & JourneyLogger::EVENT_SKIPPED_SHOW, @"");
+  GREYAssertTrue(buckets[0].min & JourneyLogger::EVENT_COMPLETED, @"");
+  GREYAssertFalse(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED, @"");
+  GREYAssertFalse(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED, @"");
+  GREYAssertTrue(
+      buckets[0].min & JourneyLogger::EVENT_HAD_INITIAL_FORM_OF_PAYMENT, @"");
+  GREYAssertTrue(
+      buckets[0].min & JourneyLogger::EVENT_HAD_NECESSARY_COMPLETE_SUGGESTIONS,
+      @"");
+  GREYAssertFalse(buckets[0].min & JourneyLogger::EVENT_REQUEST_SHIPPING, @"");
+  GREYAssertFalse(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME,
+                  @"");
+  GREYAssertFalse(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE,
+                  @"");
+  GREYAssertFalse(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL,
+                  @"");
+  GREYAssertFalse(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE,
+                  @"");
+  GREYAssertFalse(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE,
+                  @"");
+  GREYAssertTrue(
+      buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_BASIC_CARD, @"");
+  GREYAssertFalse(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_GOOGLE,
+                  @"");
+  GREYAssertFalse(buckets[0].min & JourneyLogger::EVENT_REQUEST_METHOD_OTHER,
+                  @"");
+  GREYAssertTrue(buckets[0].min & JourneyLogger::EVENT_SELECTED_CREDIT_CARD,
+                 @"");
+  GREYAssertFalse(buckets[0].min & JourneyLogger::EVENT_SELECTED_GOOGLE, @"");
+  GREYAssertFalse(buckets[0].min & JourneyLogger::EVENT_SELECTED_OTHER, @"");
+}
+
+@end
diff --git a/ios/chrome/browser/ui/payments/payment_request_manager.mm b/ios/chrome/browser/ui/payments/payment_request_manager.mm
index 85578df..1b0eac4 100644
--- a/ios/chrome/browser/ui/payments/payment_request_manager.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_manager.mm
@@ -30,10 +30,12 @@
 #include "components/payments/core/features.h"
 #include "components/payments/core/journey_logger.h"
 #include "components/payments/core/payment_address.h"
+#include "components/payments/core/payment_details.h"
 #include "components/payments/core/payment_instrument.h"
 #include "components/payments/core/payment_prefs.h"
 #include "components/payments/core/payment_request_base_delegate.h"
 #include "components/payments/core/payment_request_data_util.h"
+#include "components/payments/core/payment_shipping_option.h"
 #include "components/prefs/pref_service.h"
 #include "ios/chrome/browser/autofill/personal_data_manager_factory.h"
 #include "ios/chrome/browser/autofill/validation_rules_storage_factory.h"
@@ -760,7 +762,7 @@
   [_updateEventTimeoutTimer invalidate];
 
   const base::DictionaryValue* paymentDetailsData = nullptr;
-  web::PaymentDetails paymentDetails;
+  payments::PaymentDetails paymentDetails;
   if (!message.GetDictionary("payment_details", &paymentDetailsData)) {
     DLOG(ERROR) << "JS message parameter 'payment_details' is missing";
     return NO;
@@ -951,7 +953,7 @@
 
 - (void)paymentRequestCoordinator:(PaymentRequestCoordinator*)coordinator
           didSelectShippingOption:
-              (const web::PaymentShippingOption&)shippingOption {
+              (const payments::PaymentShippingOption&)shippingOption {
   if (coordinator.paymentRequest->state() !=
           payments::PaymentRequest::State::INTERACTIVE ||
       coordinator.paymentRequest->updating()) {
diff --git a/ios/chrome/browser/ui/payments/payment_request_mediator.mm b/ios/chrome/browser/ui/payments/payment_request_mediator.mm
index 960b4e3e..9a86bbb4 100644
--- a/ios/chrome/browser/ui/payments/payment_request_mediator.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_mediator.mm
@@ -15,6 +15,7 @@
 #include "components/payments/core/autofill_payment_instrument.h"
 #include "components/payments/core/currency_formatter.h"
 #include "components/payments/core/payment_prefs.h"
+#include "components/payments/core/payment_shipping_option.h"
 #include "components/payments/core/strings_util.h"
 #include "components/prefs/pref_service.h"
 #include "components/strings/grit/components_strings.h"
@@ -156,7 +157,7 @@
 }
 
 - (CollectionViewItem*)shippingOptionItem {
-  const web::PaymentShippingOption* option =
+  const payments::PaymentShippingOption* option =
       self.paymentRequest->selected_shipping_option();
   if (option) {
     PaymentsTextItem* item = [[PaymentsTextItem alloc] init];
diff --git a/ios/chrome/browser/ui/payments/payment_request_mediator_unittest.mm b/ios/chrome/browser/ui/payments/payment_request_mediator_unittest.mm
index 99f9ce1..76a6cb2 100644
--- a/ios/chrome/browser/ui/payments/payment_request_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_mediator_unittest.mm
@@ -13,6 +13,7 @@
 #include "components/autofill/core/browser/credit_card.h"
 #include "components/payments/core/payment_instrument.h"
 #include "components/payments/core/payment_prefs.h"
+#include "components/payments/core/payment_shipping_option.h"
 #include "components/payments/core/strings_util.h"
 #include "components/prefs/pref_service.h"
 #include "components/signin/core/browser/signin_manager.h"
@@ -103,7 +104,7 @@
 
   // Payment cannot be completed if there is no selected shipping option,
   // unless no shipping information is requested.
-  web::PaymentShippingOption* selected_shipping_option =
+  payments::PaymentShippingOption* selected_shipping_option =
       payment_request()->selected_shipping_option();
   payment_request()->set_selected_shipping_option(nullptr);
   EXPECT_FALSE([mediator() canPay]);
diff --git a/ios/chrome/browser/ui/payments/shipping_option_selection_coordinator.h b/ios/chrome/browser/ui/payments/shipping_option_selection_coordinator.h
index 9a51b59..0ea3d17 100644
--- a/ios/chrome/browser/ui/payments/shipping_option_selection_coordinator.h
+++ b/ios/chrome/browser/ui/payments/shipping_option_selection_coordinator.h
@@ -13,11 +13,8 @@
 
 namespace payments {
 class PaymentRequest;
-}  // namespace payments
-
-namespace web {
 class PaymentShippingOption;
-}  // namespace web
+}  // namespace payments
 
 @class ShippingOptionSelectionCoordinator;
 
@@ -28,7 +25,7 @@
 - (void)shippingOptionSelectionCoordinator:
             (ShippingOptionSelectionCoordinator*)coordinator
                    didSelectShippingOption:
-                       (web::PaymentShippingOption*)shippingOption;
+                       (payments::PaymentShippingOption*)shippingOption;
 
 // Notifies the delegate that the user has chosen to return to the previous
 // screen without making a selection.
diff --git a/ios/chrome/browser/ui/payments/shipping_option_selection_coordinator.mm b/ios/chrome/browser/ui/payments/shipping_option_selection_coordinator.mm
index 9351689e..21bf696e 100644
--- a/ios/chrome/browser/ui/payments/shipping_option_selection_coordinator.mm
+++ b/ios/chrome/browser/ui/payments/shipping_option_selection_coordinator.mm
@@ -6,6 +6,7 @@
 
 #include "base/logging.h"
 #include "base/strings/sys_string_conversions.h"
+#include "components/payments/core/payment_shipping_option.h"
 #include "ios/chrome/browser/payments/payment_request.h"
 #import "ios/chrome/browser/payments/payment_request_util.h"
 #include "ios/chrome/browser/ui/payments/shipping_option_selection_mediator.h"
@@ -34,7 +35,7 @@
 // notified. The delay is here to let the user get a visual feedback of the
 // selection before this view disappears.
 - (void)delayedNotifyDelegateOfSelection:
-    (web::PaymentShippingOption*)shippingOption;
+    (payments::PaymentShippingOption*)shippingOption;
 
 @end
 
@@ -101,7 +102,7 @@
 #pragma mark - Helper methods
 
 - (void)delayedNotifyDelegateOfSelection:
-    (web::PaymentShippingOption*)shippingOption {
+    (payments::PaymentShippingOption*)shippingOption {
   self.viewController.view.userInteractionEnabled = NO;
   __weak ShippingOptionSelectionCoordinator* weakSelf = self;
   dispatch_after(
diff --git a/ios/chrome/browser/ui/payments/shipping_option_selection_coordinator_unittest.mm b/ios/chrome/browser/ui/payments/shipping_option_selection_coordinator_unittest.mm
index 779b65a3..bb0cc91 100644
--- a/ios/chrome/browser/ui/payments/shipping_option_selection_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/payments/shipping_option_selection_coordinator_unittest.mm
@@ -8,6 +8,7 @@
 #include "base/test/ios/wait_util.h"
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/credit_card.h"
+#include "components/payments/core/payment_shipping_option.h"
 #include "ios/chrome/browser/payments/payment_request_test_util.h"
 #include "ios/chrome/browser/payments/test_payment_request.h"
 #import "ios/chrome/browser/ui/payments/payment_request_selector_view_controller.h"
@@ -82,7 +83,8 @@
   // Mock the coordinator delegate.
   id delegate = [OCMockObject
       mockForProtocol:@protocol(ShippingOptionSelectionCoordinatorDelegate)];
-  web::PaymentShippingOption* option = payment_request()->shipping_options()[1];
+  payments::PaymentShippingOption* option =
+      payment_request()->shipping_options()[1];
   [[delegate expect] shippingOptionSelectionCoordinator:coordinator
                                 didSelectShippingOption:option];
   [coordinator setDelegate:delegate];
diff --git a/ios/chrome/browser/ui/payments/shipping_option_selection_mediator.mm b/ios/chrome/browser/ui/payments/shipping_option_selection_mediator.mm
index 46e80af..c75af29 100644
--- a/ios/chrome/browser/ui/payments/shipping_option_selection_mediator.mm
+++ b/ios/chrome/browser/ui/payments/shipping_option_selection_mediator.mm
@@ -9,6 +9,7 @@
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/payments/core/currency_formatter.h"
+#include "components/payments/core/payment_shipping_option.h"
 #include "components/payments/core/strings_util.h"
 #include "ios/chrome/browser/payments/payment_request.h"
 #import "ios/chrome/browser/ui/payments/cells/payments_text_item.h"
@@ -91,11 +92,11 @@
 #pragma mark - Helper methods
 
 - (void)loadItems {
-  const std::vector<web::PaymentShippingOption*>& shippingOptions =
+  const std::vector<payments::PaymentShippingOption*>& shippingOptions =
       _paymentRequest->shipping_options();
   _items = [NSMutableArray arrayWithCapacity:shippingOptions.size()];
   for (size_t index = 0; index < shippingOptions.size(); ++index) {
-    web::PaymentShippingOption* shippingOption = shippingOptions[index];
+    payments::PaymentShippingOption* shippingOption = shippingOptions[index];
     DCHECK(shippingOption);
     PaymentsTextItem* item = [[PaymentsTextItem alloc] init];
     item.text = base::SysUTF16ToNSString(shippingOption->label);
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 1c5fd70..6bbcc15 100644
--- a/ios/chrome/browser/ui/tools_menu/tools_menu_constants.h
+++ b/ios/chrome/browser/ui/tools_menu/tools_menu_constants.h
@@ -55,6 +55,7 @@
   TOOLS_CLOSE_ALL_INCOGNITO_TABS = -14,
   TOOLS_VIEW_SOURCE = -15,
   TOOLS_REPORT_AN_ISSUE = -16,
+  TOOLS_SHOW_FIND_IN_PAGE = -17,
 };
 
 #endif  // IOS_CHROME_BROWSER_UI_TOOLS_MENU_TOOLS_MENU_CONSTANTS_H_
diff --git a/ios/chrome/browser/ui/tools_menu/tools_menu_model.mm b/ios/chrome/browser/ui/tools_menu/tools_menu_model.mm
index 072eeb0..c173c641 100644
--- a/ios/chrome/browser/ui/tools_menu/tools_menu_model.mm
+++ b/ios/chrome/browser/ui/tools_menu/tools_menu_model.mm
@@ -71,7 +71,8 @@
     @selector(showReportAnIssue),       ToolbarTypeAll,
     0,                                    nil },
   { IDS_IOS_TOOLS_MENU_FIND_IN_PAGE,      kToolsMenuFindInPageId,
-    IDC_FIND, nullptr,                    ToolbarTypeWebAll,
+    TOOLS_SHOW_FIND_IN_PAGE,
+    @selector(showFindInPage),            ToolbarTypeWebAll,
     0,                                    nil },
   { IDS_IOS_TOOLS_MENU_REQUEST_DESKTOP_SITE,
     kToolsMenuRequestDesktopId,
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 a2dd990..d66c97b9 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
@@ -202,7 +202,7 @@
 }
 
 - (void)setCanShowFindBar:(BOOL)enabled {
-  [self setItemEnabled:enabled withTag:IDC_FIND];
+  [self setItemEnabled:enabled withTag:TOOLS_SHOW_FIND_IN_PAGE];
 }
 
 - (void)setCanShowShareMenu:(BOOL)enabled {
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 20789b1..79c203c 100644
--- a/ios/chrome/browser/ui/tools_menu/tools_popup_controller.mm
+++ b/ios/chrome/browser/ui/tools_menu/tools_popup_controller.mm
@@ -172,7 +172,7 @@
     case TOOLS_CLOSE_ALL_INCOGNITO_TABS:
       base::RecordAction(UserMetricsAction("MobileMenuCloseAllIncognitoTabs"));
       break;
-    case IDC_FIND:
+    case TOOLS_SHOW_FIND_IN_PAGE:
       base::RecordAction(UserMetricsAction("MobileMenuFindInPage"));
       break;
     case IDC_HELP_PAGE_VIA_MENU:
diff --git a/ios/web/BUILD.gn b/ios/web/BUILD.gn
index 3b8c5d2..d0e8f90 100644
--- a/ios/web/BUILD.gn
+++ b/ios/web/BUILD.gn
@@ -63,6 +63,8 @@
     "load_committed_details.cc",
     "navigation/crw_navigation_item_holder.h",
     "navigation/crw_navigation_item_holder.mm",
+    "navigation/crw_placeholder_navigation_info.h",
+    "navigation/crw_placeholder_navigation_info.mm",
     "navigation/crw_session_controller+private_constructors.h",
     "navigation/crw_session_controller.h",
     "navigation/crw_session_controller.mm",
@@ -81,6 +83,8 @@
     "navigation/navigation_manager_util.mm",
     "navigation/nscoder_util.h",
     "navigation/nscoder_util.mm",
+    "navigation/placeholder_navigation_util.h",
+    "navigation/placeholder_navigation_util.mm",
     "navigation/serializable_user_data_manager_impl.h",
     "navigation/serializable_user_data_manager_impl.mm",
     "navigation/session_storage_builder.h",
@@ -491,6 +495,7 @@
   sources = [
     "navigation/crw_navigation_item_holder_unittest.mm",
     "navigation/crw_navigation_item_storage_unittest.mm",
+    "navigation/crw_placeholder_navigation_info_unittest.mm",
     "navigation/crw_session_controller_unittest.mm",
     "navigation/crw_session_storage_unittest.mm",
     "navigation/navigation_item_impl_unittest.mm",
@@ -499,6 +504,7 @@
     "navigation/navigation_manager_impl_unittest.mm",
     "navigation/navigation_manager_util_unittest.mm",
     "navigation/nscoder_util_unittest.mm",
+    "navigation/placeholder_navigation_util_unittest.mm",
     "navigation/serializable_user_data_manager_impl_unittest.mm",
     "navigation/wk_based_navigation_manager_impl_unittest.mm",
   ]
diff --git a/ios/web/navigation/crw_placeholder_navigation_info.h b/ios/web/navigation/crw_placeholder_navigation_info.h
new file mode 100644
index 0000000..29c640e
--- /dev/null
+++ b/ios/web/navigation/crw_placeholder_navigation_info.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 IOS_WEB_NAVIGATION_CRW_PLACEHOLDER_NAVIGATION_INFO_H_
+#define IOS_WEB_NAVIGATION_CRW_PLACEHOLDER_NAVIGATION_INFO_H_
+
+#import <WebKit/WebKit.h>
+
+#import "base/ios/block_types.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+// An NSObject wrapper for a completion handler for a placeholder navigation.
+//
+// A placeholder navigation is an "about:blank" page loaded into the WKWebView
+// that corresponds to Native View or WebUI URL. This navigation is inserted to
+// generate a WKBackForwardListItem for the Native View or WebUI URL in the
+// WebView so that the WKBackForwardList contains the full list of user-visible
+// navigations.
+//
+// Because loading in WKWebView is asynchronous, this object is attached to the
+// WKNavigation for the placeholder hold, and the completion handler is expected
+// to be executed in WKNavigationDelegate's |didFinishNavigation| callback to
+// trigger the NativeView or WebUI HTML load.
+@interface CRWPlaceholderNavigationInfo : NSObject
+
+// Create a new instance that encapsulates a completion handler to be executed
+// when |navigation| is finished.
++ (instancetype)createForNavigation:(WKNavigation*)navigation
+              withCompletionHandler:(ProceduralBlock)completionHandler;
+
+// Returns the CRWPlaceholderNavigationInfo associated with |navigation|.
++ (nullable CRWPlaceholderNavigationInfo*)infoForNavigation:
+    (nullable WKNavigation*)navigation;
+
+// Runs the completion handler saved in this object.
+- (void)runCompletionHandler;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+#endif  // IOS_WEB_NAVIGATION_CRW_PLACEHOLDER_NAVIGATION_INFO_H_
diff --git a/ios/web/navigation/crw_placeholder_navigation_info.mm b/ios/web/navigation/crw_placeholder_navigation_info.mm
new file mode 100644
index 0000000..b549682
--- /dev/null
+++ b/ios/web/navigation/crw_placeholder_navigation_info.mm
@@ -0,0 +1,61 @@
+// 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 "ios/web/navigation/crw_placeholder_navigation_info.h"
+
+#import <objc/runtime.h>
+
+#include "base/logging.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+// The address of this static variable is used to set and get the is-placeholder
+// flag value from a WKNavigation object. A WKNavigation is marked as a
+// placeholder if it is created by |loadPlaceholderInWebViewForURL|. Placeholder
+// navigations are used to create placeholder WKBackForwardListItems that
+// correspond to Native View or WebUI URLs.
+const void* kPlaceholderNavigationKey = &kPlaceholderNavigationKey;
+
+@interface CRWPlaceholderNavigationInfo ()
+
+// Initializes a new instance wrapping |handler|.
+- (instancetype)initWithCompletionHandler:(ProceduralBlock)handler
+    NS_DESIGNATED_INITIALIZER;
+
+@end
+
+@implementation CRWPlaceholderNavigationInfo {
+  ProceduralBlock _completionHandler;
+}
+
++ (instancetype)createForNavigation:(nonnull WKNavigation*)navigation
+              withCompletionHandler:(ProceduralBlock)handler {
+  DCHECK(navigation);
+  CRWPlaceholderNavigationInfo* info =
+      [[CRWPlaceholderNavigationInfo alloc] initWithCompletionHandler:handler];
+  objc_setAssociatedObject(navigation, &kPlaceholderNavigationKey, info,
+                           OBJC_ASSOCIATION_RETAIN);
+  return info;
+}
+
++ (nullable CRWPlaceholderNavigationInfo*)infoForNavigation:
+    (nullable WKNavigation*)navigation {
+  return objc_getAssociatedObject(navigation, &kPlaceholderNavigationKey);
+}
+
+- (instancetype)initWithCompletionHandler:(ProceduralBlock)handler {
+  self = [super init];
+  if (self) {
+    _completionHandler = [handler copy];
+  }
+  return self;
+}
+
+- (void)runCompletionHandler {
+  _completionHandler();
+}
+
+@end
diff --git a/ios/web/navigation/crw_placeholder_navigation_info_unittest.mm b/ios/web/navigation/crw_placeholder_navigation_info_unittest.mm
new file mode 100644
index 0000000..958193b
--- /dev/null
+++ b/ios/web/navigation/crw_placeholder_navigation_info_unittest.mm
@@ -0,0 +1,41 @@
+// 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 "ios/web/navigation/crw_placeholder_navigation_info.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+#include "third_party/ocmock/OCMock/OCMock.h"
+
+// Test fixture for CRWPlaceholderNavigationInfo.
+typedef PlatformTest CRWPlaceholderNavigationInfoTest;
+
+// Tests that completion handler is saved and retrieved from a navigation.
+TEST_F(CRWPlaceholderNavigationInfoTest, SetInfoForNavigation) {
+  WKNavigation* navigation = OCMClassMock([WKNavigation class]);
+  EXPECT_NSEQ(nil, [CRWPlaceholderNavigationInfo infoForNavigation:navigation]);
+
+  __block BOOL called = NO;
+  ProceduralBlock completionHandler = ^{
+    called = YES;
+  };
+
+  CRWPlaceholderNavigationInfo* info =
+      [CRWPlaceholderNavigationInfo createForNavigation:navigation
+                                  withCompletionHandler:completionHandler];
+  EXPECT_EQ(NO, called);
+
+  CRWPlaceholderNavigationInfo* retrievedInfo =
+      [CRWPlaceholderNavigationInfo infoForNavigation:navigation];
+  ASSERT_NSEQ(info, retrievedInfo);
+  EXPECT_EQ(NO, called);
+
+  [retrievedInfo runCompletionHandler];
+  EXPECT_EQ(YES, called);
+}
+
+TEST_F(CRWPlaceholderNavigationInfoTest, GetInfoOnNilNavigationReturnsNil) {
+  EXPECT_NSEQ(nil, [CRWPlaceholderNavigationInfo infoForNavigation:nil]);
+}
diff --git a/ios/web/navigation/placeholder_navigation_util.h b/ios/web/navigation/placeholder_navigation_util.h
new file mode 100644
index 0000000..cda2a68c
--- /dev/null
+++ b/ios/web/navigation/placeholder_navigation_util.h
@@ -0,0 +1,35 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_WEB_NAVIGATION_PLACEHOLDER_NAVIGATION_UTIL_H_
+#define IOS_WEB_NAVIGATION_PLACEHOLDER_NAVIGATION_UTIL_H_
+
+#include "url/gurl.h"
+
+// Utility functions for creating and managing URLs for placeholder navigations.
+// A placeholder navigation is an "about:blank" page loaded into the WKWebView
+// that corresponds to Native View or WebUI URL. This navigation is inserted to
+// generate a WKBackForwardListItem for the Native View or WebUI URL in the
+// WebView so that the WKBackForwardList contains the full list of user-visible
+// navigations.
+// See "Handling App-specific URLs" section in go/bling-navigation-experiment
+// for more details.
+
+namespace web {
+namespace placeholder_navigation_util {
+
+// Returns true if |URL| is a placeholder navigation URL.
+bool IsPlaceholderUrl(const GURL& url);
+
+// Creates the URL for the placeholder navigation required for Native View and
+// WebUI URLs.
+GURL CreatePlaceholderUrlForUrl(const GURL& original_url);
+
+// Extracts the original URL from the placeholder URL.
+GURL ExtractUrlFromPlaceholderUrl(const GURL& url);
+
+}  // namespace placeholder_navigation_util
+}  // namespace web
+
+#endif  // IOS_WEB_NAVIGATION_PLACEHOLDER_NAVIGATION_UTIL_H_
diff --git a/ios/web/navigation/placeholder_navigation_util.mm b/ios/web/navigation/placeholder_navigation_util.mm
new file mode 100644
index 0000000..cdfadef3
--- /dev/null
+++ b/ios/web/navigation/placeholder_navigation_util.mm
@@ -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 "ios/web/navigation/placeholder_navigation_util.h"
+
+#include <string>
+
+#include "base/strings/string_util.h"
+#include "net/base/escape.h"
+#include "net/base/url_util.h"
+
+namespace web {
+namespace placeholder_navigation_util {
+
+bool IsPlaceholderUrl(const GURL& url) {
+  return url.IsAboutBlank() &&
+         base::StartsWith(url.query(), "for=", base::CompareCase::SENSITIVE);
+}
+
+GURL CreatePlaceholderUrlForUrl(const GURL& original_url) {
+  if (!original_url.is_valid())
+    return GURL::EmptyGURL();
+
+  GURL::Replacements query_replacements;
+  std::string encoded = "for=" + net::EscapeQueryParamValue(
+                                     original_url.spec(), false /* use_plus */);
+  query_replacements.SetQueryStr(encoded);
+  GURL placeholder_url =
+      GURL(url::kAboutBlankURL).ReplaceComponents(query_replacements);
+  DCHECK(placeholder_url.is_valid());
+  return placeholder_url;
+}
+
+GURL ExtractUrlFromPlaceholderUrl(const GURL& url) {
+  std::string value;
+  if (IsPlaceholderUrl(url) && net::GetValueForKeyInQuery(url, "for", &value)) {
+    GURL decoded_url(value);
+    if (decoded_url.is_valid())
+      return decoded_url;
+  }
+  return GURL::EmptyGURL();
+}
+
+}  // namespace placeholder_navigation_util
+}  // namespace
diff --git a/ios/web/navigation/placeholder_navigation_util_unittest.mm b/ios/web/navigation/placeholder_navigation_util_unittest.mm
new file mode 100644
index 0000000..98998f8
--- /dev/null
+++ b/ios/web/navigation/placeholder_navigation_util_unittest.mm
@@ -0,0 +1,54 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/web/navigation/placeholder_navigation_util.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace web {
+namespace placeholder_navigation_util {
+
+typedef PlatformTest PlaceholderNavigationUtilTest;
+
+TEST_F(PlaceholderNavigationUtilTest, IsPlaceholderUrl) {
+  // Valid placeholder URLs.
+  EXPECT_TRUE(IsPlaceholderUrl(GURL("about:blank?for=")));
+  EXPECT_TRUE(IsPlaceholderUrl(GURL("about:blank?for=chrome%3A%2F%2Fnewtab")));
+
+  // Not an about:blank URL.
+  EXPECT_FALSE(IsPlaceholderUrl(GURL::EmptyGURL()));
+  // Missing ?for= query parameter.
+  EXPECT_FALSE(IsPlaceholderUrl(GURL("about:blank")));
+  EXPECT_FALSE(IsPlaceholderUrl(GURL("about:blank?chrome:%3A%2F%2Fnewtab")));
+}
+
+TEST_F(PlaceholderNavigationUtilTest, EncodReturnsEmptyOnInvalidUrls) {
+  EXPECT_EQ(GURL::EmptyGURL(), CreatePlaceholderUrlForUrl(GURL::EmptyGURL()));
+  EXPECT_EQ(GURL::EmptyGURL(), CreatePlaceholderUrlForUrl(GURL("notaurl")));
+}
+
+TEST_F(PlaceholderNavigationUtilTest, EncodeDecodeValidUrls) {
+  {
+    GURL original("chrome://chrome-urls");
+    GURL encoded("about:blank?for=chrome%3A%2F%2Fchrome-urls");
+    EXPECT_EQ(encoded, CreatePlaceholderUrlForUrl(original));
+    EXPECT_EQ(original, ExtractUrlFromPlaceholderUrl(encoded));
+  }
+  {
+    GURL original("about:blank");
+    GURL encoded("about:blank?for=about%3Ablank");
+    EXPECT_EQ(encoded, CreatePlaceholderUrlForUrl(original));
+    EXPECT_EQ(original, ExtractUrlFromPlaceholderUrl(encoded));
+  }
+}
+
+// Tests that invalid URLs will be rejected in decoding.
+TEST_F(PlaceholderNavigationUtilTest, DecodeRejectInvalidUrls) {
+  GURL encoded("about:blank?for=thisisnotanurl");
+  EXPECT_EQ(GURL::EmptyGURL(), ExtractUrlFromPlaceholderUrl(encoded));
+}
+
+}  // namespace placeholder_navigation_util
+}  // namespace web
diff --git a/ios/web/navigation/wk_based_navigation_manager_impl.mm b/ios/web/navigation/wk_based_navigation_manager_impl.mm
index 37f882f4..17689717 100644
--- a/ios/web/navigation/wk_based_navigation_manager_impl.mm
+++ b/ios/web/navigation/wk_based_navigation_manager_impl.mm
@@ -300,6 +300,7 @@
 void WKBasedNavigationManagerImpl::GoBack() {
   if (transient_item_) {
     transient_item_.reset();
+    delegate_->ClearTransientContent();
     return;
   }
   [delegate_->GetWebViewNavigationProxy() goBack];
diff --git a/ios/web/payments/payment_request.cc b/ios/web/payments/payment_request.cc
index 63ff82d..83baf63 100644
--- a/ios/web/payments/payment_request.cc
+++ b/ios/web/payments/payment_request.cc
@@ -5,7 +5,6 @@
 #include "ios/web/public/payments/payment_request.h"
 
 #include "base/json/json_reader.h"
-#include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
@@ -15,22 +14,6 @@
 // All of these are defined here (even though most are only used once each) so
 // the format details are easy to locate and update or compare to the spec doc.
 // (https://w3c.github.io/browser-payment-api/).
-static const char kPaymentCurrencyAmountCurrencySystemISO4217[] =
-    "urn:iso:std:iso:4217";
-static const char kPaymentCurrencyAmountCurrencySystem[] = "currencySystem";
-static const char kPaymentCurrencyAmountCurrency[] = "currency";
-static const char kPaymentCurrencyAmountValue[] = "value";
-static const char kPaymentDetailsId[] = "id";
-static const char kPaymentDetailsDisplayItems[] = "displayItems";
-static const char kPaymentDetailsError[] = "error";
-static const char kPaymentDetailsShippingOptions[] = "shippingOptions";
-static const char kPaymentDetailsTotal[] = "total";
-static const char kPaymentDetailsModifierSupportedMethods[] =
-    "supportedMethods";
-static const char kPaymentDetailsModifierTotal[] = "total";
-static const char kPaymentItemAmount[] = "amount";
-static const char kPaymentItemLabel[] = "label";
-static const char kPaymentItemPending[] = "pending";
 static const char kPaymentOptionsRequestPayerEmail[] = "requestPayerEmail";
 static const char kPaymentOptionsRequestPayerName[] = "requestPayerName";
 static const char kPaymentOptionsRequestPayerPhone[] = "requestPayerPhone";
@@ -50,10 +33,6 @@
 static const char kPaymentResponsePayerPhone[] = "payerPhone";
 static const char kPaymentResponseShippingAddress[] = "shippingAddress";
 static const char kPaymentResponseShippingOption[] = "shippingOption";
-static const char kPaymentShippingOptionAmount[] = "amount";
-static const char kPaymentShippingOptionId[] = "id";
-static const char kPaymentShippingOptionLabel[] = "label";
-static const char kPaymentShippingOptionSelected[] = "selected";
 
 }  // namespace
 
@@ -62,240 +41,6 @@
 const char kPaymentRequestIDExternal[] = "payment-request-id";
 const char kPaymentRequestDataExternal[] = "payment-request-data";
 
-PaymentCurrencyAmount::PaymentCurrencyAmount()
-    // By default, the currency is defined by [ISO4217]. For example, USD for
-    // US Dollars.
-    : currency_system(
-          base::ASCIIToUTF16(kPaymentCurrencyAmountCurrencySystemISO4217)) {}
-
-PaymentCurrencyAmount::~PaymentCurrencyAmount() = default;
-
-bool PaymentCurrencyAmount::operator==(
-    const PaymentCurrencyAmount& other) const {
-  return this->currency == other.currency && this->value == other.value;
-}
-
-bool PaymentCurrencyAmount::operator!=(
-    const PaymentCurrencyAmount& other) const {
-  return !(*this == other);
-}
-
-bool PaymentCurrencyAmount::FromDictionaryValue(
-    const base::DictionaryValue& value) {
-  if (!value.GetString(kPaymentCurrencyAmountCurrency, &this->currency)) {
-    return false;
-  }
-
-  if (!value.GetString(kPaymentCurrencyAmountValue, &this->value)) {
-    return false;
-  }
-
-  // Currency_system is optional
-  value.GetString(kPaymentCurrencyAmountCurrencySystem, &this->currency_system);
-
-  return true;
-}
-
-std::unique_ptr<base::DictionaryValue>
-PaymentCurrencyAmount::ToDictionaryValue() const {
-  std::unique_ptr<base::DictionaryValue> result =
-      base::MakeUnique<base::DictionaryValue>();
-
-  result->SetString(kPaymentCurrencyAmountCurrency, this->currency);
-  result->SetString(kPaymentCurrencyAmountValue, this->value);
-  if (!this->currency_system.empty())
-    result->SetString(kPaymentCurrencyAmountCurrencySystem,
-                      this->currency_system);
-
-  return result;
-}
-
-PaymentItem::PaymentItem() : pending(false) {}
-PaymentItem::~PaymentItem() = default;
-
-bool PaymentItem::operator==(const PaymentItem& other) const {
-  return this->label == other.label && this->amount == other.amount &&
-         this->pending == other.pending;
-}
-
-bool PaymentItem::operator!=(const PaymentItem& other) const {
-  return !(*this == other);
-}
-
-bool PaymentItem::FromDictionaryValue(const base::DictionaryValue& value) {
-  if (!value.GetString(kPaymentItemLabel, &this->label)) {
-    return false;
-  }
-
-  const base::DictionaryValue* amount_dict = nullptr;
-  if (!value.GetDictionary(kPaymentItemAmount, &amount_dict)) {
-    return false;
-  }
-  if (!this->amount.FromDictionaryValue(*amount_dict)) {
-    return false;
-  }
-
-  // Pending is optional.
-  value.GetBoolean(kPaymentItemPending, &this->pending);
-
-  return true;
-}
-
-std::unique_ptr<base::DictionaryValue> PaymentItem::ToDictionaryValue() const {
-  std::unique_ptr<base::DictionaryValue> result =
-      base::MakeUnique<base::DictionaryValue>();
-
-  result->SetString(kPaymentItemLabel, this->label);
-  result->SetDictionary(kPaymentItemAmount, this->amount.ToDictionaryValue());
-  result->SetBoolean(kPaymentItemPending, this->pending);
-
-  return result;
-}
-
-PaymentShippingOption::PaymentShippingOption() : selected(false) {}
-PaymentShippingOption::PaymentShippingOption(
-    const PaymentShippingOption& other) = default;
-PaymentShippingOption::~PaymentShippingOption() = default;
-
-bool PaymentShippingOption::operator==(
-    const PaymentShippingOption& other) const {
-  return this->id == other.id && this->label == other.label &&
-         this->amount == other.amount && this->selected == other.selected;
-}
-
-bool PaymentShippingOption::operator!=(
-    const PaymentShippingOption& other) const {
-  return !(*this == other);
-}
-
-bool PaymentShippingOption::FromDictionaryValue(
-    const base::DictionaryValue& value) {
-  if (!value.GetString(kPaymentShippingOptionId, &this->id)) {
-    return false;
-  }
-
-  if (!value.GetString(kPaymentShippingOptionLabel, &this->label)) {
-    return false;
-  }
-
-  const base::DictionaryValue* amount_dict = nullptr;
-  if (!value.GetDictionary(kPaymentShippingOptionAmount, &amount_dict)) {
-    return false;
-  }
-  if (!this->amount.FromDictionaryValue(*amount_dict)) {
-    return false;
-  }
-
-  // Selected is optional.
-  value.GetBoolean(kPaymentShippingOptionSelected, &this->selected);
-
-  return true;
-}
-
-PaymentDetailsModifier::PaymentDetailsModifier() {}
-PaymentDetailsModifier::PaymentDetailsModifier(
-    const PaymentDetailsModifier& other) = default;
-PaymentDetailsModifier::~PaymentDetailsModifier() = default;
-
-bool PaymentDetailsModifier::operator==(
-    const PaymentDetailsModifier& other) const {
-  return this->supported_methods == other.supported_methods &&
-         this->total == other.total &&
-         this->additional_display_items == other.additional_display_items;
-}
-
-bool PaymentDetailsModifier::operator!=(
-    const PaymentDetailsModifier& other) const {
-  return !(*this == other);
-}
-
-std::unique_ptr<base::DictionaryValue>
-PaymentDetailsModifier::ToDictionaryValue() const {
-  std::unique_ptr<base::DictionaryValue> result =
-      base::MakeUnique<base::DictionaryValue>();
-
-  std::unique_ptr<base::ListValue> methods =
-      base::MakeUnique<base::ListValue>();
-  size_t numMethods = this->supported_methods.size();
-  for (size_t i = 0; i < numMethods; i++) {
-    methods->GetList().emplace_back(this->supported_methods[i]);
-  }
-  result->SetList(kPaymentDetailsModifierSupportedMethods, std::move(methods));
-  result->SetDictionary(kPaymentDetailsModifierTotal,
-                        this->total.ToDictionaryValue());
-
-  return result;
-}
-
-PaymentDetails::PaymentDetails() {}
-PaymentDetails::PaymentDetails(const PaymentDetails& other) = default;
-PaymentDetails::~PaymentDetails() = default;
-
-bool PaymentDetails::operator==(const PaymentDetails& other) const {
-  return this->id == other.id && this->total == other.total &&
-         this->display_items == other.display_items &&
-         this->shipping_options == other.shipping_options &&
-         this->modifiers == other.modifiers && this->error == other.error;
-}
-
-bool PaymentDetails::operator!=(const PaymentDetails& other) const {
-  return !(*this == other);
-}
-
-bool PaymentDetails::FromDictionaryValue(const base::DictionaryValue& value,
-                                         bool requires_total) {
-  this->display_items.clear();
-  this->shipping_options.clear();
-  this->modifiers.clear();
-
-  // ID is optional.
-  value.GetString(kPaymentDetailsId, &this->id);
-
-  const base::DictionaryValue* total_dict = nullptr;
-  if (!value.GetDictionary(kPaymentDetailsTotal, &total_dict) &&
-      requires_total) {
-    return false;
-  }
-  if (total_dict && !this->total.FromDictionaryValue(*total_dict)) {
-    return false;
-  }
-
-  const base::ListValue* display_items_list = nullptr;
-  if (value.GetList(kPaymentDetailsDisplayItems, &display_items_list)) {
-    for (size_t i = 0; i < display_items_list->GetSize(); ++i) {
-      const base::DictionaryValue* payment_item_dict;
-      if (!display_items_list->GetDictionary(i, &payment_item_dict)) {
-        return false;
-      }
-      PaymentItem payment_item;
-      if (!payment_item.FromDictionaryValue(*payment_item_dict)) {
-        return false;
-      }
-      this->display_items.push_back(payment_item);
-    }
-  }
-
-  const base::ListValue* shipping_options_list = nullptr;
-  if (value.GetList(kPaymentDetailsShippingOptions, &shipping_options_list)) {
-    for (size_t i = 0; i < shipping_options_list->GetSize(); ++i) {
-      const base::DictionaryValue* shipping_option_dict;
-      if (!shipping_options_list->GetDictionary(i, &shipping_option_dict)) {
-        return false;
-      }
-      PaymentShippingOption shipping_option;
-      if (!shipping_option.FromDictionaryValue(*shipping_option_dict)) {
-        return false;
-      }
-      this->shipping_options.push_back(shipping_option);
-    }
-  }
-
-  // Error is optional.
-  value.GetString(kPaymentDetailsError, &this->error);
-
-  return true;
-}
-
 PaymentOptions::PaymentOptions()
     : request_payer_name(false),
       request_payer_email(false),
diff --git a/ios/web/payments/payment_request_unittest.cc b/ios/web/payments/payment_request_unittest.cc
index 515942c..9c2a17f5 100644
--- a/ios/web/payments/payment_request_unittest.cc
+++ b/ios/web/payments/payment_request_unittest.cc
@@ -10,201 +10,12 @@
 #include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
-#include "components/payments/core/basic_card_response.h"
-#include "components/payments/core/payment_address.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace web {
 
 // PaymentRequest parsing tests.
 
-// Tests the success case when populating a PaymentCurrencyAmount from a
-// dictionary.
-TEST(PaymentRequestTest, PaymentCurrencyAmountFromDictionaryValueSuccess) {
-  PaymentCurrencyAmount expected;
-  expected.currency = base::ASCIIToUTF16("AUD");
-  expected.value = base::ASCIIToUTF16("-438.23");
-
-  base::DictionaryValue amount_dict;
-  amount_dict.SetString("currency", "AUD");
-  amount_dict.SetString("value", "-438.23");
-
-  PaymentCurrencyAmount actual;
-  EXPECT_TRUE(actual.FromDictionaryValue(amount_dict));
-
-  EXPECT_EQ(expected, actual);
-
-  expected.currency_system = base::ASCIIToUTF16("urn:iso:std:iso:123456789");
-  amount_dict.SetString("currencySystem", "urn:iso:std:iso:123456789");
-  EXPECT_TRUE(actual.FromDictionaryValue(amount_dict));
-  EXPECT_EQ(expected, actual);
-}
-
-// Tests the failure case when populating a PaymentCurrencyAmount from a
-// dictionary.
-TEST(PaymentRequestTest, PaymentCurrencyAmountFromDictionaryValueFailure) {
-  // Both a currency and a value are required.
-  PaymentCurrencyAmount actual;
-  base::DictionaryValue amount_dict;
-  EXPECT_FALSE(actual.FromDictionaryValue(amount_dict));
-
-  // Both values must be strings.
-  amount_dict.SetInteger("currency", 842);
-  amount_dict.SetString("value", "-438.23");
-  EXPECT_FALSE(actual.FromDictionaryValue(amount_dict));
-
-  amount_dict.SetString("currency", "NZD");
-  amount_dict.SetDouble("value", -438.23);
-  EXPECT_FALSE(actual.FromDictionaryValue(amount_dict));
-}
-
-// Tests the success case when populating a PaymentItem from a dictionary.
-TEST(PaymentRequestTest, PaymentItemFromDictionaryValueSuccess) {
-  PaymentItem expected;
-  expected.label = base::ASCIIToUTF16("Payment Total");
-  expected.amount.currency = base::ASCIIToUTF16("NZD");
-  expected.amount.value = base::ASCIIToUTF16("2,242,093.00");
-
-  base::DictionaryValue item_dict;
-  item_dict.SetString("label", "Payment Total");
-  std::unique_ptr<base::DictionaryValue> amount_dict(new base::DictionaryValue);
-  amount_dict->SetString("currency", "NZD");
-  amount_dict->SetString("value", "2,242,093.00");
-  item_dict.Set("amount", std::move(amount_dict));
-
-  PaymentItem actual;
-  EXPECT_TRUE(actual.FromDictionaryValue(item_dict));
-
-  EXPECT_EQ(expected, actual);
-}
-
-// Tests the failure case when populating a PaymentItem from a dictionary.
-TEST(PaymentRequestTest, PaymentItemFromDictionaryValueFailure) {
-  // Both a label and an amount are required.
-  PaymentItem actual;
-  base::DictionaryValue item_dict;
-  EXPECT_FALSE(actual.FromDictionaryValue(item_dict));
-
-  item_dict.SetString("label", "Payment Total");
-  EXPECT_FALSE(actual.FromDictionaryValue(item_dict));
-
-  // Even with both present, the label must be a string.
-  std::unique_ptr<base::DictionaryValue> amount_dict(new base::DictionaryValue);
-  amount_dict->SetString("currency", "NZD");
-  amount_dict->SetString("value", "2,242,093.00");
-  item_dict.Set("amount", std::move(amount_dict));
-  item_dict.SetInteger("label", 42);
-  EXPECT_FALSE(actual.FromDictionaryValue(item_dict));
-}
-
-// Tests the success case when populating a PaymentDetails from a dictionary.
-TEST(PaymentRequestTest, PaymentDetailsFromDictionaryValueSuccess) {
-  PaymentDetails expected;
-  expected.error = base::ASCIIToUTF16("Error in details");
-
-  base::DictionaryValue details_dict;
-  details_dict.SetString("error", "Error in details");
-  PaymentDetails actual;
-  EXPECT_TRUE(
-      actual.FromDictionaryValue(details_dict, /*requires_total=*/false));
-  EXPECT_EQ(expected, actual);
-
-  expected.total.label = base::ASCIIToUTF16("TOTAL");
-  expected.total.amount.currency = base::ASCIIToUTF16("GBP");
-  expected.total.amount.value = base::ASCIIToUTF16("6.66");
-
-  std::unique_ptr<base::DictionaryValue> total_dict(new base::DictionaryValue);
-  total_dict->SetString("label", "TOTAL");
-  std::unique_ptr<base::DictionaryValue> amount_dict(new base::DictionaryValue);
-  amount_dict->SetString("currency", "GBP");
-  amount_dict->SetString("value", "6.66");
-  total_dict->Set("amount", std::move(amount_dict));
-  details_dict.Set("total", std::move(total_dict));
-
-  EXPECT_TRUE(
-      actual.FromDictionaryValue(details_dict, /*requires_total=*/false));
-  EXPECT_EQ(expected, actual);
-
-  EXPECT_TRUE(
-      actual.FromDictionaryValue(details_dict, /*requires_total=*/true));
-  EXPECT_EQ(expected, actual);
-}
-
-// Tests the failure case when populating a PaymentDetails from a dictionary.
-TEST(PaymentRequestTest, PaymentDetailsFromDictionaryValueFailure) {
-  PaymentDetails expected;
-  expected.total.label = base::ASCIIToUTF16("TOTAL");
-  expected.total.amount.currency = base::ASCIIToUTF16("GBP");
-  expected.total.amount.value = base::ASCIIToUTF16("6.66");
-  expected.error = base::ASCIIToUTF16("Error in details");
-
-  base::DictionaryValue details_dict;
-  details_dict.SetString("error", "Error in details");
-
-  PaymentDetails actual;
-  EXPECT_FALSE(
-      actual.FromDictionaryValue(details_dict, /*requires_total=*/true));
-}
-
-// Tests the success case when populating a PaymentShippingOption from a
-// dictionary.
-TEST(PaymentRequestTest, PaymentShippingOptionFromDictionaryValueSuccess) {
-  PaymentShippingOption expected;
-  expected.id = base::ASCIIToUTF16("123");
-  expected.label = base::ASCIIToUTF16("Ground Shipping");
-  expected.amount.currency = base::ASCIIToUTF16("BRL");
-  expected.amount.value = base::ASCIIToUTF16("4,000.32");
-  expected.selected = true;
-
-  base::DictionaryValue shipping_option_dict;
-  shipping_option_dict.SetString("id", "123");
-  shipping_option_dict.SetString("label", "Ground Shipping");
-  std::unique_ptr<base::DictionaryValue> amount_dict(new base::DictionaryValue);
-  amount_dict->SetString("currency", "BRL");
-  amount_dict->SetString("value", "4,000.32");
-  shipping_option_dict.Set("amount", std::move(amount_dict));
-  shipping_option_dict.SetBoolean("selected", true);
-
-  PaymentShippingOption actual;
-  EXPECT_TRUE(actual.FromDictionaryValue(shipping_option_dict));
-
-  EXPECT_EQ(expected, actual);
-}
-
-// Tests the failure case when populating a PaymentShippingOption from a
-// dictionary.
-TEST(PaymentRequestTest, PaymentShippingOptionFromDictionaryValueFailure) {
-  PaymentShippingOption expected;
-  expected.id = base::ASCIIToUTF16("123");
-  expected.label = base::ASCIIToUTF16("Ground Shipping");
-  expected.amount.currency = base::ASCIIToUTF16("BRL");
-  expected.amount.value = base::ASCIIToUTF16("4,000.32");
-  expected.selected = true;
-
-  PaymentShippingOption actual;
-  base::DictionaryValue shipping_option_dict;
-
-  // Id, Label, and amount are required.
-  shipping_option_dict.SetString("id", "123");
-  EXPECT_FALSE(actual.FromDictionaryValue(shipping_option_dict));
-
-  shipping_option_dict.SetString("label", "Ground Shipping");
-  EXPECT_FALSE(actual.FromDictionaryValue(shipping_option_dict));
-
-  // Id must be a string.
-  std::unique_ptr<base::DictionaryValue> amount_dict(new base::DictionaryValue);
-  amount_dict->SetString("currency", "BRL");
-  amount_dict->SetString("value", "4,000.32");
-  shipping_option_dict.Set("amount", std::move(amount_dict));
-  shipping_option_dict.SetInteger("id", 123);
-  EXPECT_FALSE(actual.FromDictionaryValue(shipping_option_dict));
-
-  // Label must be a string.
-  shipping_option_dict.SetString("id", "123");
-  shipping_option_dict.SetInteger("label", 123);
-  EXPECT_FALSE(actual.FromDictionaryValue(shipping_option_dict));
-}
-
 // Tests that populating a PaymentRequest from an empty dictionary fails.
 TEST(PaymentRequestTest, ParsingEmptyRequestDictionaryFails) {
   PaymentRequest output_request;
@@ -314,138 +125,6 @@
 
 // PaymentRequest serialization tests.
 
-// Tests that serializing a default PaymentCurrencyAmount yields the expected
-// result.
-TEST(PaymentRequestTest, EmptyPaymentCurrencyAmountDictionary) {
-  base::DictionaryValue expected_value;
-
-  expected_value.SetString("currency", "");
-  expected_value.SetString("value", "");
-  expected_value.SetString("currencySystem", "urn:iso:std:iso:4217");
-
-  PaymentCurrencyAmount payment_currency_amount;
-  EXPECT_TRUE(
-      expected_value.Equals(payment_currency_amount.ToDictionaryValue().get()));
-}
-
-// Tests that serializing a populated PaymentCurrencyAmount yields the expected
-// result.
-TEST(PaymentRequestTest, PopulatedCurrencyAmountDictionary) {
-  base::DictionaryValue expected_value;
-
-  expected_value.SetString("currency", "AUD");
-  expected_value.SetString("value", "-438.23");
-  expected_value.SetString("currencySystem", "urn:iso:std:iso:123456789");
-
-  PaymentCurrencyAmount payment_currency_amount;
-  payment_currency_amount.currency = base::ASCIIToUTF16("AUD");
-  payment_currency_amount.value = base::ASCIIToUTF16("-438.23");
-  payment_currency_amount.currency_system =
-      base::ASCIIToUTF16("urn:iso:std:iso:123456789");
-
-  EXPECT_TRUE(
-      expected_value.Equals(payment_currency_amount.ToDictionaryValue().get()));
-}
-
-// Tests that serializing a default PaymentItem yields the expected result.
-TEST(PaymentRequestTest, EmptyPaymentItemDictionary) {
-  base::DictionaryValue expected_value;
-
-  expected_value.SetString("label", "");
-  std::unique_ptr<base::DictionaryValue> amount_dict =
-      base::MakeUnique<base::DictionaryValue>();
-  amount_dict->SetString("currency", "");
-  amount_dict->SetString("value", "");
-  amount_dict->SetString("currencySystem", "urn:iso:std:iso:4217");
-  expected_value.SetDictionary("amount", std::move(amount_dict));
-  expected_value.SetBoolean("pending", false);
-
-  PaymentItem payment_item;
-  EXPECT_TRUE(expected_value.Equals(payment_item.ToDictionaryValue().get()));
-}
-
-// Tests that serializing a populated PaymentItem yields the expected result.
-TEST(PaymentRequestTest, PopulatedPaymentItemDictionary) {
-  base::DictionaryValue expected_value;
-
-  expected_value.SetString("label", "Payment Total");
-  std::unique_ptr<base::DictionaryValue> amount_dict =
-      base::MakeUnique<base::DictionaryValue>();
-  amount_dict->SetString("currency", "NZD");
-  amount_dict->SetString("value", "2,242,093.00");
-  amount_dict->SetString("currencySystem", "urn:iso:std:iso:4217");
-  expected_value.SetDictionary("amount", std::move(amount_dict));
-  expected_value.SetBoolean("pending", true);
-
-  PaymentItem payment_item;
-  payment_item.label = base::ASCIIToUTF16("Payment Total");
-  payment_item.amount.currency = base::ASCIIToUTF16("NZD");
-  payment_item.amount.value = base::ASCIIToUTF16("2,242,093.00");
-  payment_item.pending = true;
-
-  EXPECT_TRUE(expected_value.Equals(payment_item.ToDictionaryValue().get()));
-}
-
-// Tests that serializing a default PaymentDetailsModifier yields the expected
-// result.
-TEST(PaymentRequestTest, EmptyPaymentDetailsModifierDictionary) {
-  base::DictionaryValue expected_value;
-
-  std::unique_ptr<base::ListValue> supported_methods_list =
-      base::MakeUnique<base::ListValue>();
-  expected_value.SetList("supportedMethods", std::move(supported_methods_list));
-  std::unique_ptr<base::DictionaryValue> item_dict =
-      base::MakeUnique<base::DictionaryValue>();
-  item_dict->SetString("label", "");
-  std::unique_ptr<base::DictionaryValue> amount_dict =
-      base::MakeUnique<base::DictionaryValue>();
-  amount_dict->SetString("currency", "");
-  amount_dict->SetString("value", "");
-  amount_dict->SetString("currencySystem", "urn:iso:std:iso:4217");
-  item_dict->SetDictionary("amount", std::move(amount_dict));
-  item_dict->SetBoolean("pending", false);
-  expected_value.SetDictionary("total", std::move(item_dict));
-
-  PaymentDetailsModifier payment_detials_modififer;
-  EXPECT_TRUE(expected_value.Equals(
-      payment_detials_modififer.ToDictionaryValue().get()));
-}
-
-// Tests that serializing a populated PaymentDetailsModifier yields the expected
-// result.
-TEST(PaymentRequestTest, PopulatedDetailsModifierDictionary) {
-  base::DictionaryValue expected_value;
-
-  std::unique_ptr<base::ListValue> supported_methods_list =
-      base::MakeUnique<base::ListValue>();
-  supported_methods_list->GetList().emplace_back("visa");
-  supported_methods_list->GetList().emplace_back("amex");
-  expected_value.SetList("supportedMethods", std::move(supported_methods_list));
-  std::unique_ptr<base::DictionaryValue> item_dict =
-      base::MakeUnique<base::DictionaryValue>();
-  item_dict->SetString("label", "Gratuity");
-  std::unique_ptr<base::DictionaryValue> amount_dict =
-      base::MakeUnique<base::DictionaryValue>();
-  amount_dict->SetString("currency", "USD");
-  amount_dict->SetString("value", "139.99");
-  amount_dict->SetString("currencySystem", "urn:iso:std:iso:4217");
-  item_dict->SetDictionary("amount", std::move(amount_dict));
-  item_dict->SetBoolean("pending", false);
-  expected_value.SetDictionary("total", std::move(item_dict));
-
-  PaymentDetailsModifier payment_detials_modififer;
-  payment_detials_modififer.supported_methods.push_back(
-      base::ASCIIToUTF16("visa"));
-  payment_detials_modififer.supported_methods.push_back(
-      base::ASCIIToUTF16("amex"));
-  payment_detials_modififer.total.label = base::ASCIIToUTF16("Gratuity");
-  payment_detials_modififer.total.amount.currency = base::ASCIIToUTF16("USD");
-  payment_detials_modififer.total.amount.value = base::ASCIIToUTF16("139.99");
-
-  EXPECT_TRUE(expected_value.Equals(
-      payment_detials_modififer.ToDictionaryValue().get()));
-}
-
 // Tests that serializing a default PaymentResponse yields the expected result.
 TEST(PaymentRequestTest, EmptyResponseDictionary) {
   base::DictionaryValue expected_value;
@@ -544,207 +223,6 @@
 
 // Value equality tests.
 
-// Tests that two currency amount objects are not equal if their property values
-// differ or one is missing a value present in the other, and equal otherwise.
-TEST(PaymentRequestTest, PaymentCurrencyAmountEquality) {
-  PaymentCurrencyAmount currency_amount1;
-  PaymentCurrencyAmount currency_amount2;
-  EXPECT_EQ(currency_amount1, currency_amount2);
-
-  currency_amount1.currency = base::ASCIIToUTF16("HKD");
-  EXPECT_NE(currency_amount1, currency_amount2);
-  currency_amount2.currency = base::ASCIIToUTF16("USD");
-  EXPECT_NE(currency_amount1, currency_amount2);
-  currency_amount2.currency = base::ASCIIToUTF16("HKD");
-  EXPECT_EQ(currency_amount1, currency_amount2);
-
-  currency_amount1.value = base::ASCIIToUTF16("49.89");
-  EXPECT_NE(currency_amount1, currency_amount2);
-  currency_amount2.value = base::ASCIIToUTF16("49.99");
-  EXPECT_NE(currency_amount1, currency_amount2);
-  currency_amount2.value = base::ASCIIToUTF16("49.89");
-  EXPECT_EQ(currency_amount1, currency_amount2);
-}
-
-// Tests that two payment item objects are not equal if their property values
-// differ or one is missing a value present in the other, and equal otherwise.
-// Doesn't test all properties of child objects, relying instead on their
-// respective tests.
-TEST(PaymentRequestTest, PaymentItemEquality) {
-  PaymentItem item1;
-  PaymentItem item2;
-  EXPECT_EQ(item1, item2);
-
-  item1.label = base::ASCIIToUTF16("Subtotal");
-  EXPECT_NE(item1, item2);
-  item2.label = base::ASCIIToUTF16("Total");
-  EXPECT_NE(item1, item2);
-  item2.label = base::ASCIIToUTF16("Subtotal");
-  EXPECT_EQ(item1, item2);
-
-  item1.amount.value = base::ASCIIToUTF16("104.34");
-  EXPECT_NE(item1, item2);
-  item2.amount.value = base::ASCIIToUTF16("104");
-  EXPECT_NE(item1, item2);
-  item2.amount.value = base::ASCIIToUTF16("104.34");
-  EXPECT_EQ(item1, item2);
-
-  item1.pending = true;
-  EXPECT_NE(item1, item2);
-  item2.pending = true;
-  EXPECT_EQ(item1, item2);
-}
-
-// Tests that two shipping option objects are not equal if their property values
-// differ or one is missing a value present in the other, and equal otherwise.
-// Doesn't test all properties of child objects, relying instead on their
-// respective tests.
-TEST(PaymentRequestTest, PaymentShippingOptionEquality) {
-  PaymentShippingOption shipping_option1;
-  PaymentShippingOption shipping_option2;
-  EXPECT_EQ(shipping_option1, shipping_option2);
-
-  shipping_option1.id = base::ASCIIToUTF16("a8df2");
-  EXPECT_NE(shipping_option1, shipping_option2);
-  shipping_option2.id = base::ASCIIToUTF16("k42jk");
-  EXPECT_NE(shipping_option1, shipping_option2);
-  shipping_option2.id = base::ASCIIToUTF16("a8df2");
-  EXPECT_EQ(shipping_option1, shipping_option2);
-
-  shipping_option1.label = base::ASCIIToUTF16("Overnight");
-  EXPECT_NE(shipping_option1, shipping_option2);
-  shipping_option2.label = base::ASCIIToUTF16("Ground");
-  EXPECT_NE(shipping_option1, shipping_option2);
-  shipping_option2.label = base::ASCIIToUTF16("Overnight");
-  EXPECT_EQ(shipping_option1, shipping_option2);
-
-  shipping_option1.amount.currency = base::ASCIIToUTF16("AUD");
-  EXPECT_NE(shipping_option1, shipping_option2);
-  shipping_option2.amount.currency = base::ASCIIToUTF16("HKD");
-  EXPECT_NE(shipping_option1, shipping_option2);
-  shipping_option2.amount.currency = base::ASCIIToUTF16("AUD");
-  EXPECT_EQ(shipping_option1, shipping_option2);
-
-  shipping_option1.selected = true;
-  EXPECT_NE(shipping_option1, shipping_option2);
-  shipping_option2.selected = true;
-  EXPECT_EQ(shipping_option1, shipping_option2);
-}
-
-// Tests that two details modifier objects are not equal if their property
-// values differ or one is missing a value present in the other, and equal
-// otherwise. Doesn't test all properties of child objects, relying instead on
-// their respective tests.
-TEST(PaymentRequestTest, PaymentDetailsModifierEquality) {
-  PaymentDetailsModifier details_modifier1;
-  PaymentDetailsModifier details_modifier2;
-  EXPECT_EQ(details_modifier1, details_modifier2);
-
-  std::vector<base::string16> supported_methods1;
-  supported_methods1.push_back(base::ASCIIToUTF16("China UnionPay"));
-  supported_methods1.push_back(base::ASCIIToUTF16("BobPay"));
-  details_modifier1.supported_methods = supported_methods1;
-  EXPECT_NE(details_modifier1, details_modifier2);
-  std::vector<base::string16> supported_methods2;
-  supported_methods2.push_back(base::ASCIIToUTF16("BobPay"));
-  details_modifier2.supported_methods = supported_methods2;
-  EXPECT_NE(details_modifier1, details_modifier2);
-  details_modifier2.supported_methods = supported_methods1;
-  EXPECT_EQ(details_modifier1, details_modifier2);
-
-  details_modifier1.total.label = base::ASCIIToUTF16("Total");
-  EXPECT_NE(details_modifier1, details_modifier2);
-  details_modifier2.total.label = base::ASCIIToUTF16("Gratuity");
-  EXPECT_NE(details_modifier1, details_modifier2);
-  details_modifier2.total.label = base::ASCIIToUTF16("Total");
-  EXPECT_EQ(details_modifier1, details_modifier2);
-
-  PaymentItem payment_item;
-  payment_item.label = base::ASCIIToUTF16("Tax");
-  std::vector<PaymentItem> display_items1;
-  display_items1.push_back(payment_item);
-  details_modifier1.additional_display_items = display_items1;
-  EXPECT_NE(details_modifier1, details_modifier2);
-  std::vector<PaymentItem> display_items2;
-  display_items2.push_back(payment_item);
-  display_items2.push_back(payment_item);
-  details_modifier2.additional_display_items = display_items2;
-  EXPECT_NE(details_modifier1, details_modifier2);
-  details_modifier2.additional_display_items = display_items1;
-  EXPECT_EQ(details_modifier1, details_modifier2);
-}
-
-// Tests that two payment details objects are not equal if their property values
-// differ or one is missing a value present in the other, and equal otherwise.
-// Doesn't test all properties of child objects, relying instead on their
-// respective tests.
-TEST(PaymentRequestTest, PaymentDetailsEquality) {
-  PaymentDetails details1;
-  PaymentDetails details2;
-  EXPECT_EQ(details1, details2);
-
-  details1.id = "12345";
-  EXPECT_NE(details1, details2);
-  details2.id = "54321";
-  EXPECT_NE(details1, details2);
-  details2.id = details1.id;
-  EXPECT_EQ(details1, details2);
-
-  details1.total.label = base::ASCIIToUTF16("Total");
-  EXPECT_NE(details1, details2);
-  details2.total.label = base::ASCIIToUTF16("Shipping");
-  EXPECT_NE(details1, details2);
-  details2.total.label = base::ASCIIToUTF16("Total");
-  EXPECT_EQ(details1, details2);
-
-  details1.error = base::ASCIIToUTF16("Foo");
-  EXPECT_NE(details1, details2);
-  details2.error = base::ASCIIToUTF16("Bar");
-  EXPECT_NE(details1, details2);
-  details2.error = base::ASCIIToUTF16("Foo");
-  EXPECT_EQ(details1, details2);
-
-  PaymentItem payment_item;
-  payment_item.label = base::ASCIIToUTF16("Tax");
-  std::vector<PaymentItem> display_items1;
-  display_items1.push_back(payment_item);
-  details1.display_items = display_items1;
-  EXPECT_NE(details1, details2);
-  std::vector<PaymentItem> display_items2;
-  display_items2.push_back(payment_item);
-  display_items2.push_back(payment_item);
-  details2.display_items = display_items2;
-  EXPECT_NE(details1, details2);
-  details2.display_items = display_items1;
-  EXPECT_EQ(details1, details2);
-
-  PaymentShippingOption shipping_option;
-  shipping_option.label = base::ASCIIToUTF16("Overnight");
-  std::vector<PaymentShippingOption> shipping_options1;
-  shipping_options1.push_back(shipping_option);
-  details1.shipping_options = shipping_options1;
-  EXPECT_NE(details1, details2);
-  std::vector<PaymentShippingOption> shipping_options2;
-  shipping_options2.push_back(shipping_option);
-  shipping_options2.push_back(shipping_option);
-  details2.shipping_options = shipping_options2;
-  EXPECT_NE(details1, details2);
-  details2.shipping_options = shipping_options1;
-  EXPECT_EQ(details1, details2);
-
-  PaymentDetailsModifier details_modifier;
-  details_modifier.total.label = base::ASCIIToUTF16("Total");
-  std::vector<PaymentDetailsModifier> details_modifiers1;
-  details_modifiers1.push_back(details_modifier);
-  details1.modifiers = details_modifiers1;
-  EXPECT_NE(details1, details2);
-  std::vector<PaymentDetailsModifier> details_modifiers2;
-  details2.modifiers = details_modifiers2;
-  EXPECT_NE(details1, details2);
-  details2.modifiers = details_modifiers1;
-  EXPECT_EQ(details1, details2);
-}
-
 // Tests that two payment options objects are not equal if their property values
 // differ and equal otherwise.
 TEST(PaymentRequestTest, PaymentOptionsEquality) {
@@ -828,11 +306,11 @@
   request2.method_data = method_data1;
   EXPECT_EQ(request1, request2);
 
-  PaymentDetails details1;
+  payments::PaymentDetails details1;
   details1.total.label = base::ASCIIToUTF16("Total");
   request1.details = details1;
   EXPECT_NE(request1, request2);
-  PaymentDetails details2;
+  payments::PaymentDetails details2;
   details2.total.amount.value = base::ASCIIToUTF16("0.01");
   request2.details = details2;
   EXPECT_NE(request1, request2);
diff --git a/ios/web/public/payments/payment_request.h b/ios/web/public/payments/payment_request.h
index a5353b1c..9db32a73 100644
--- a/ios/web/public/payments/payment_request.h
+++ b/ios/web/public/payments/payment_request.h
@@ -12,9 +12,14 @@
 #include "base/strings/string16.h"
 #include "components/payments/core/basic_card_response.h"
 #include "components/payments/core/payment_address.h"
+#include "components/payments/core/payment_details.h"
 #include "components/payments/core/payment_method_data.h"
 #include "components/payments/core/payment_options_provider.h"
 
+// TODO(crbug.com/759167): Web layer is not supposed to depend on components.
+// Move definitions and implementations of PaymentOptions, PaymentRequest, and
+// PaymentResponse to components/payments/core or ios/chrome/browser/payments.
+
 // C++ bindings for the PaymentRequest API. Conforms to the following specs:
 // https://w3c.github.io/browser-payment-api/ (18 July 2016 editor's draft)
 // https://w3c.github.io/webpayments-methods-card/ (31 May 2016 editor's draft)
@@ -30,170 +35,6 @@
 extern const char kPaymentRequestIDExternal[];
 extern const char kPaymentRequestDataExternal[];
 
-// Supplies monetary amounts.
-class PaymentCurrencyAmount {
- public:
-  PaymentCurrencyAmount();
-  ~PaymentCurrencyAmount();
-
-  bool operator==(const PaymentCurrencyAmount& other) const;
-  bool operator!=(const PaymentCurrencyAmount& other) const;
-
-  // Populates the properties of this PaymentCurrencyAmount from |value|.
-  // Returns true if the required values are present.
-  bool FromDictionaryValue(const base::DictionaryValue& value);
-
-  // Creates a base::DictionaryValue with the properties of this
-  // PaymentCurrencyAmount.
-  std::unique_ptr<base::DictionaryValue> ToDictionaryValue() const;
-
-  // A currency identifier. The most common identifiers are three-letter
-  // alphabetic codes as defined by ISO 4217 (for example, "USD" for US Dollars)
-  // however any string is considered valid.
-  base::string16 currency;
-
-  // A string containing the decimal monetary value.
-  base::string16 value;
-
-  // A URL that indicates the currency system that the currency identifier
-  // belongs to.
-  base::string16 currency_system;
-};
-
-// Information indicating what the payment request is for and the value asked
-// for.
-class PaymentItem {
- public:
-  PaymentItem();
-  ~PaymentItem();
-
-  bool operator==(const PaymentItem& other) const;
-  bool operator!=(const PaymentItem& other) const;
-
-  // Populates the properties of this PaymentItem from |value|. Returns true if
-  // the required values are present.
-  bool FromDictionaryValue(const base::DictionaryValue& value);
-
-  // Creates a base::DictionaryValue with the properties of this
-  // PaymentItem.
-  std::unique_ptr<base::DictionaryValue> ToDictionaryValue() const;
-
-  // A human-readable description of the item.
-  base::string16 label;
-
-  // The monetary amount for the item.
-  PaymentCurrencyAmount amount;
-
-  // When set to true this flag means that the amount field is not final. This
-  // is commonly used to show items such as shipping or tax amounts that depend
-  // upon selection of shipping address or shipping option.
-  bool pending;
-};
-
-// Information describing a shipping option.
-class PaymentShippingOption {
- public:
-  PaymentShippingOption();
-  PaymentShippingOption(const PaymentShippingOption& other);
-  ~PaymentShippingOption();
-
-  bool operator==(const PaymentShippingOption& other) const;
-  bool operator!=(const PaymentShippingOption& other) const;
-
-  // Populates the properties of this PaymentShippingOption from |value|.
-  // Returns true if the required values are present.
-  bool FromDictionaryValue(const base::DictionaryValue& value);
-
-  // An identifier used to reference this PaymentShippingOption. It is unique
-  // for a given PaymentRequest.
-  base::string16 id;
-
-  // A human-readable description of the item. The user agent should use this
-  // string to display the shipping option to the user.
-  base::string16 label;
-
-  // A PaymentCurrencyAmount containing the monetary amount for the option.
-  PaymentCurrencyAmount amount;
-
-  // This is set to true to indicate that this is the default selected
-  // PaymentShippingOption in a sequence. User agents should display this option
-  // by default in the user interface.
-  bool selected;
-};
-
-// Details that modify the PaymentDetails based on the payment method
-// identifier.
-class PaymentDetailsModifier {
- public:
-  PaymentDetailsModifier();
-  PaymentDetailsModifier(const PaymentDetailsModifier& other);
-  ~PaymentDetailsModifier();
-
-  bool operator==(const PaymentDetailsModifier& other) const;
-  bool operator!=(const PaymentDetailsModifier& other) const;
-
-  // Creates a base::DictionaryValue with the properties of this
-  // PaymentDetailsModifier.
-  std::unique_ptr<base::DictionaryValue> ToDictionaryValue() const;
-
-  // A sequence of payment method identifiers. The remaining fields in the
-  // PaymentDetailsModifier apply only if the user selects a payment method
-  // included in this sequence.
-  std::vector<base::string16> supported_methods;
-
-  // This value overrides the total field in the PaymentDetails dictionary for
-  // the payment method identifiers in the supportedMethods field.
-  PaymentItem total;
-
-  // Provides additional display items that are appended to the displayItems
-  // field in the PaymentDetails dictionary for the payment method identifiers
-  // in the supportedMethods field. This field is commonly used to add a
-  // discount or surcharge line item indicating the reason for the different
-  // total amount for the selected payment method that the user agent may
-  // display.
-  std::vector<PaymentItem> additional_display_items;
-};
-
-// Details about the requested transaction.
-class PaymentDetails {
- public:
-  PaymentDetails();
-  PaymentDetails(const PaymentDetails& other);
-  ~PaymentDetails();
-
-  bool operator==(const PaymentDetails& other) const;
-  bool operator!=(const PaymentDetails& other) const;
-
-  // Populates the properties of this PaymentDetails from |value|. Returns true
-  // if the required values are present. If |requires_total| is true, the total
-  // property has to be present.
-  bool FromDictionaryValue(const base::DictionaryValue& value,
-                           bool requires_total);
-
-  // The unique free-form identifier for this payment request.
-  std::string id;
-
-  // The total amount of the payment request.
-  PaymentItem total;
-
-  // Line items for the payment request that the user agent may display. For
-  // example, it might include details of products or breakdown of tax and
-  // shipping.
-  std::vector<PaymentItem> display_items;
-
-  // The different shipping options for the user to choose from. If empty, this
-  // indicates that the merchant cannot ship to the current shipping address.
-  std::vector<PaymentShippingOption> shipping_options;
-
-  // Modifiers for particular payment method identifiers. For example, it allows
-  // adjustment to the total amount based on payment method.
-  std::vector<PaymentDetailsModifier> modifiers;
-
-  // If non-empty, this is the error message the user agent should display to
-  // the user when the payment request is updated using updateWith.
-  base::string16 error;
-};
-
 // Information describing a shipping option.
 class PaymentOptions {
  public:
@@ -260,7 +101,7 @@
   // Properties set via the constructor for communicating from the page to the
   // browser UI.
   std::vector<payments::PaymentMethodData> method_data;
-  PaymentDetails details;
+  payments::PaymentDetails details;
   PaymentOptions options;
 };
 
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index 5618c48..17c70f9 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -39,10 +39,12 @@
 #import "ios/net/nsurlrequest_util.h"
 #include "ios/web/history_state_util.h"
 #import "ios/web/interstitials/web_interstitial_impl.h"
+#import "ios/web/navigation/crw_placeholder_navigation_info.h"
 #import "ios/web/navigation/crw_session_controller.h"
 #import "ios/web/navigation/navigation_item_impl.h"
 #import "ios/web/navigation/navigation_manager_impl.h"
 #include "ios/web/navigation/navigation_manager_util.h"
+#include "ios/web/navigation/placeholder_navigation_util.h"
 #include "ios/web/net/cert_host_pair.h"
 #import "ios/web/net/crw_cert_verification_controller.h"
 #import "ios/web/net/crw_ssl_status_updater.h"
@@ -118,6 +120,10 @@
 
 namespace {
 
+using web::placeholder_navigation_util::IsPlaceholderUrl;
+using web::placeholder_navigation_util::CreatePlaceholderUrlForUrl;
+using web::placeholder_navigation_util::ExtractUrlFromPlaceholderUrl;
+
 // Struct to capture data about a user interaction. Records the time of the
 // interaction and the main document URL at that time.
 struct UserInteractionEvent {
@@ -567,6 +573,13 @@
 // Updates the WKBackForwardListItemHolder navigation item.
 - (void)updateCurrentBackForwardListItemHolder;
 
+// Loads a blank page directly into WKWebView as a placeholder for a Native View
+// or WebUI URL. This page has the URL about:blank?for=<encoded original URL>.
+// The completion handler is called in the |webView:didFinishNavigation|
+// callback of the placeholder navigation. See "Handling App-specific URLs"
+// section of go/bling-navigation-experiment for details.
+- (void)loadPlaceholderInWebViewForURL:(const GURL&)originalURL
+                     completionHandler:(ProceduralBlock)completionHandler;
 // Loads the current nativeController in a native view. If a web view is
 // present, removes it and swaps in the native view in its place. |context| can
 // not be null.
@@ -1022,11 +1035,20 @@
   [result addEntriesFromDictionary:@{
     @"estimatedProgress" : @"webViewEstimatedProgressDidChange",
     @"hasOnlySecureContent" : @"webViewSecurityFeaturesDidChange",
-    @"loading" : @"webViewLoadingStateDidChange",
-    @"title" : @"webViewTitleDidChange",
-    @"URL" : @"webViewURLDidChange",
+    @"title" : @"webViewTitleDidChange"
   }];
 
+  // WKBasedNavigationManagerImpl does not need (and is incompatible with) the
+  // state maintenance carried out in URL and Loading state KVO handlers.
+  // TODO(crbug.com/738020): Refactor navigaton related KVO functionality into
+  // NavigationManager subclasses to avoid ad-hoc switches like this.
+  if (!web::GetWebClient()->IsSlimNavigationManagerEnabled()) {
+    [result addEntriesFromDictionary:@{
+      @"loading" : @"webViewLoadingStateDidChange",
+      @"URL" : @"webViewURLDidChange",
+    }];
+  }
+
   return result;
 }
 
@@ -1185,7 +1207,14 @@
 
 - (GURL)currentURLWithTrustLevel:(web::URLVerificationTrustLevel*)trustLevel {
   DCHECK(trustLevel) << "Verification of the trustLevel state is mandatory";
-  if (_webView) {
+
+  // The web view URL is the current URL only if it is not a placeholder URL.
+  // In case of a placeholder navigation, the visible URL is the app-specific
+  // one in the native controller.
+  // TODO(crbug.com/738020): Investigate if this method is still needed and if
+  // it can be implemented using NavigationManager API after removal of legacy
+  // navigation stack.
+  if (_webView && !IsPlaceholderUrl(net::GURLWithNSURL(_webView.URL))) {
     return [self webURLWithTrustLevel:trustLevel];
   }
   // Any non-web URL source is trusted.
@@ -1353,9 +1382,6 @@
 }
 
 - (id<CRWWebViewNavigationProxy>)webViewNavigationProxy {
-  DCHECK(
-      !self.webView ||
-      [self.webView conformsToProtocol:@protocol(CRWWebViewNavigationProxy)]);
   return static_cast<id<CRWWebViewNavigationProxy>>(self.webView);
 }
 
@@ -1728,31 +1754,59 @@
   [self loadNativeViewWithSuccess:NO navigationContext:context];
 }
 
-// Loads the current URL in a native controller, retrieved from the native
-// provider.
+// Loads the current URL in a native controller if using the legacy navigation
+// stack. If the new navigation stack is used, start loading a placeholder
+// into the web view, upon the completion of which the native controller will
+// be triggered.
 - (void)loadCurrentURLInNativeView {
-  // Free the web view.
-  [self removeWebView];
+  ProceduralBlock finishLoadCurrentURLInNativeView = ^{
+    web::NavigationItem* item = self.currentNavItem;
+    const GURL targetURL = item ? item->GetURL() : GURL::EmptyGURL();
+    const web::Referrer referrer;
+    id<CRWNativeContent> nativeContent =
+        [_nativeProvider controllerForURL:targetURL webState:self.webState];
+    // Unlike the WebView case, always create a new controller and view.
+    // TODO(crbug.com/759178): What to do if this does return nil?
+    [self setNativeController:nativeContent];
+    if ([nativeContent respondsToSelector:@selector(virtualURL)]) {
+      item->SetVirtualURL([nativeContent virtualURL]);
+    }
 
-  web::NavigationItem* item = self.currentNavItem;
-  const GURL targetURL = item ? item->GetURL() : GURL::EmptyGURL();
-  const web::Referrer referrer;
-  id<CRWNativeContent> nativeContent =
-      [_nativeProvider controllerForURL:targetURL webState:self.webState];
-  // Unlike the WebView case, always create a new controller and view.
-  // TODO(pinkerton): What to do if this does return nil?
-  [self setNativeController:nativeContent];
-  if ([nativeContent respondsToSelector:@selector(virtualURL)]) {
-    item->SetVirtualURL([nativeContent virtualURL]);
+    std::unique_ptr<web::NavigationContextImpl> navigationContext =
+        [self registerLoadRequestForURL:targetURL
+                               referrer:referrer
+                             transition:self.currentTransition
+                 sameDocumentNavigation:NO];
+    [self loadNativeViewWithSuccess:YES
+                  navigationContext:navigationContext.get()];
+  };
+
+  if (!web::GetWebClient()->IsSlimNavigationManagerEnabled()) {
+    // Free the web view.
+    [self removeWebView];
+    finishLoadCurrentURLInNativeView();
+  } else {
+    web::NavigationItem* item = self.currentNavItem;
+    DCHECK(item);
+    [self loadPlaceholderInWebViewForURL:item->GetVirtualURL()
+                       completionHandler:finishLoadCurrentURLInNativeView];
   }
+}
 
-  std::unique_ptr<web::NavigationContextImpl> navigationContext =
-      [self registerLoadRequestForURL:targetURL
-                             referrer:referrer
-                           transition:self.currentTransition
-               sameDocumentNavigation:NO];
-  [self loadNativeViewWithSuccess:YES
-                navigationContext:navigationContext.get()];
+- (void)loadPlaceholderInWebViewForURL:(const GURL&)originalURL
+                     completionHandler:(ProceduralBlock)completionHandler {
+  web::WebClient* webClient = web::GetWebClient();
+  DCHECK(webClient->IsSlimNavigationManagerEnabled() &&
+         webClient->IsAppSpecificURL(originalURL));
+
+  GURL placeholderURL = CreatePlaceholderUrlForUrl(originalURL);
+  [self ensureWebViewCreated];
+
+  NSURLRequest* request =
+      [NSURLRequest requestWithURL:net::NSURLWithGURL(placeholderURL)];
+  WKNavigation* navigation = [_webView loadRequest:request];
+  [CRWPlaceholderNavigationInfo createForNavigation:navigation
+                              withCompletionHandler:completionHandler];
 }
 
 - (void)willLoadCurrentItemWithURL:(const GURL&)URL {
@@ -3976,7 +4030,20 @@
 
 - (void)loadHTML:(NSString*)HTML forAppSpecificURL:(const GURL&)URL {
   CHECK(web::GetWebClient()->IsAppSpecificURL(URL));
-  [self loadHTML:HTML forURL:URL];
+
+  ProceduralBlock finishLoadHTMLForAppSpecificURL = ^{
+    [self loadHTML:HTML forURL:URL];
+  };
+
+  // When using WKBasedNavigationManagerImpl, a placeholder must be loaded into
+  // the web view for each WebUI page so that the WKBackForwardList has an entry
+  // for each user-visible navigation.
+  if (web::GetWebClient()->IsSlimNavigationManagerEnabled()) {
+    [self loadPlaceholderInWebViewForURL:URL
+                       completionHandler:finishLoadHTMLForAppSpecificURL];
+  } else {
+    finishLoadHTMLForAppSpecificURL();
+  }
 }
 
 - (void)stopLoading {
@@ -4113,12 +4180,20 @@
     return;
   }
 
+  GURL requestURL = net::GURLWithNSURL(action.request.URL);
+
+  // If this is a placeholder navigation, pass through.
+  if (web::GetWebClient()->IsSlimNavigationManagerEnabled() &&
+      IsPlaceholderUrl(requestURL)) {
+    decisionHandler(WKNavigationActionPolicyAllow);
+    return;
+  }
+
   // The page will not be changed until this navigation is committed, so the
   // retrieved state will be pending until |didCommitNavigation| callback.
   [self updatePendingNavigationInfoFromNavigationAction:action];
 
   // Invalid URLs should not be loaded.
-  GURL requestURL = net::GURLWithNSURL(action.request.URL);
   if (!requestURL.is_valid()) {
     decisionHandler(WKNavigationActionPolicyCancel);
     // The HTML5 spec indicates that window.open with an invalid URL should open
@@ -4156,6 +4231,15 @@
     decidePolicyForNavigationResponse:(WKNavigationResponse*)navigationResponse
                       decisionHandler:
                           (void (^)(WKNavigationResponsePolicy))handler {
+  GURL responseURL = net::GURLWithNSURL(navigationResponse.response.URL);
+
+  // If this is a placeholder navigation, pass through.
+  if (web::GetWebClient()->IsSlimNavigationManagerEnabled() &&
+      IsPlaceholderUrl(responseURL)) {
+    handler(WKNavigationResponsePolicyAllow);
+    return;
+  }
+
   if ([navigationResponse.response isKindOfClass:[NSHTTPURLResponse class]]) {
     // Create HTTP headers from the response.
     // TODO(crbug.com/546157): Due to the limited interface of
@@ -4184,8 +4268,7 @@
   }
   if ([self.passKitDownloader
           isMIMETypePassKitType:[_pendingNavigationInfo MIMEType]]) {
-    GURL URL = net::GURLWithNSURL(navigationResponse.response.URL);
-    [self.passKitDownloader downloadPassKitFileWithURL:URL];
+    [self.passKitDownloader downloadPassKitFileWithURL:responseURL];
     allowNavigation = NO;
 
     // Discard the pending PassKit entry to ensure that the current URL is not
@@ -4209,10 +4292,42 @@
 
 - (void)webView:(WKWebView*)webView
     didStartProvisionalNavigation:(WKNavigation*)navigation {
+  GURL webViewURL = net::GURLWithNSURL(webView.URL);
+
+  // If this is a placeholder URL, there are only two possibilities:
+  // 1. This navigation is initiated by |loadPlaceholderInWebViewForURL| in
+  //    preparation for loading a native controller or WebUI.
+  // In this case, do not update the page navigation states as they will be
+  // updated by the completion handler of the placeholder navigation.
+  //
+  // 2. This is a back-forward navigation to an app-specific URL.
+  // In this case, restart the app-specific URL load to properly capture state.
+  if (web::GetWebClient()->IsSlimNavigationManagerEnabled() &&
+      IsPlaceholderUrl(webViewURL)) {
+    GURL originalURL = ExtractUrlFromPlaceholderUrl(webViewURL);
+    if (!originalURL.is_valid() ||
+        !web::GetWebClient()->IsAppSpecificURL(originalURL)) {
+      // Encoded URL is not a recognized app-specific URL. Abort to be safe.
+      [self abortLoad];
+      return;
+    }
+
+    // Back-forward navigation to placeholder URL.
+    // TODO(crbug.com/760113): This implementation destroys forward history.
+    // Investigate if we can rely on WKWebView's back/forward navigation and
+    // only reload the native controller / WebUI portion to preserve forward
+    // history.
+    if (![CRWPlaceholderNavigationInfo infoForNavigation:navigation]) {
+      [self abortLoad];
+      NavigationManager::WebLoadParams params(originalURL);
+      self.navigationManagerImpl->LoadURLWithParams(params);
+    }
+    return;
+  }
+
   [_navigationStates setState:web::WKNavigationState::STARTED
                 forNavigation:navigation];
 
-  GURL webViewURL = net::GURLWithNSURL(webView.URL);
   if (webViewURL.is_empty()) {
     // May happen on iOS9, however in didCommitNavigation: callback the URL
     // will be "about:blank".
@@ -4255,6 +4370,15 @@
     // dangerous.
     if (web::GetWebClient()->IsAppSpecificURL(_documentURL)) {
       [self abortLoad];
+
+      // Do some additional book keeping for WKBasedNavigationManagerImpl, which
+      // doesn't use KVO to manage navigation states. Sometimes
+      // WKNavigationDelegate callbacks may arrive after calling |stopLoading|.
+      // Remove this navigation from |_navigationStates| allows those delinquent
+      // callbacks to be ignored.
+      if (web::GetWebClient()->IsSlimNavigationManagerEnabled()) {
+        [_navigationStates removeNavigation:navigation];
+      }
       NavigationManager::WebLoadParams params(webViewURL);
       self.webState->GetNavigationManager()->LoadURLWithParams(params);
     }
@@ -4270,13 +4394,19 @@
 
 - (void)webView:(WKWebView*)webView
     didReceiveServerRedirectForProvisionalNavigation:(WKNavigation*)navigation {
+  GURL webViewURL = net::GURLWithNSURL(webView.URL);
+
+  // This callback should never be triggered for placeholder navigations.
+  DCHECK(!(web::GetWebClient()->IsSlimNavigationManagerEnabled() &&
+           IsPlaceholderUrl(webViewURL)));
+
   [_navigationStates setState:web::WKNavigationState::REDIRECTED
                 forNavigation:navigation];
 
   // It is fine to ignore returned NavigationContext. Context does not change
   // for redirect and old context stored _navigationStates is valid and it
   // should not be replaced.
-  [self registerLoadRequestForURL:net::GURLWithNSURL(webView.URL)
+  [self registerLoadRequestForURL:webViewURL
                          referrer:[self currentReferrer]
                        transition:ui::PAGE_TRANSITION_SERVER_REDIRECT
            sameDocumentNavigation:NO];
@@ -4334,6 +4464,19 @@
 
 - (void)webView:(WKWebView*)webView
     didCommitNavigation:(WKNavigation*)navigation {
+  GURL webViewURL = net::GURLWithNSURL(webView.URL);
+
+  // If this is a placeholder navigation or if |navigation| has been previous
+  // aborted, return without modifying the navigation states. The latter case
+  // seems to happen due to asychronous nature of WKWebView; sometimes
+  // |didCommitNavigation| callback arrives after |stopLoading| has been called.
+  if (web::GetWebClient()->IsSlimNavigationManagerEnabled() &&
+      (IsPlaceholderUrl(webViewURL) ||
+       [_navigationStates stateForNavigation:navigation] ==
+           web::WKNavigationState::NONE)) {
+    return;
+  }
+
   [self displayWebView];
 
   bool navigationFinished = [_navigationStates stateForNavigation:navigation] ==
@@ -4348,7 +4491,7 @@
 
   // This is the point where the document's URL has actually changed, and
   // pending navigation information should be applied to state information.
-  [self setDocumentURL:net::GURLWithNSURL([_webView URL])];
+  [self setDocumentURL:webViewURL];
 
   if (!_lastRegisteredRequestURL.is_valid() &&
       _documentURL != _lastRegisteredRequestURL) {
@@ -4442,6 +4585,27 @@
 
 - (void)webView:(WKWebView*)webView
     didFinishNavigation:(WKNavigation*)navigation {
+  GURL webViewURL = net::GURLWithNSURL(webView.URL);
+
+  // If this is a placeholder navigation for an app-specific URL, finish
+  // loading by running the completion handler.
+  if (web::GetWebClient()->IsSlimNavigationManagerEnabled()) {
+    if (IsPlaceholderUrl(webViewURL)) {
+      CRWPlaceholderNavigationInfo* placeholderNavigationInfo =
+          [CRWPlaceholderNavigationInfo infoForNavigation:navigation];
+      if (placeholderNavigationInfo) {
+        [placeholderNavigationInfo runCompletionHandler];
+      }
+      return;
+    }
+    // Sometimes |didFinishNavigation| callback arrives after |stopLoading| has
+    // been called. Abort in this case.
+    if ([_navigationStates stateForNavigation:navigation] ==
+        web::WKNavigationState::NONE) {
+      return;
+    }
+  }
+
   bool navigationCommitted =
       [_navigationStates stateForNavigation:navigation] ==
       web::WKNavigationState::COMMITTED;
@@ -4466,6 +4630,17 @@
 - (void)webView:(WKWebView*)webView
     didFailNavigation:(WKNavigation*)navigation
             withError:(NSError*)error {
+  // This callback should never be triggered for placeholder navigations.
+  if (web::GetWebClient()->IsSlimNavigationManagerEnabled()) {
+    DCHECK(!IsPlaceholderUrl(net::GURLWithNSURL(webView.URL)));
+    // Sometimes |didFailNavigation| callback arrives after |stopLoading| has
+    // been called. Abort in this case.
+    if ([_navigationStates stateForNavigation:navigation] ==
+        web::WKNavigationState::NONE) {
+      return;
+    }
+  }
+
   [_navigationStates setState:web::WKNavigationState::FAILED
                 forNavigation:navigation];
 
@@ -4481,6 +4656,10 @@
                     completionHandler:
                         (void (^)(NSURLSessionAuthChallengeDisposition,
                                   NSURLCredential*))completionHandler {
+  // This callback should never be triggered for placeholder navigations.
+  DCHECK(!(web::GetWebClient()->IsSlimNavigationManagerEnabled() &&
+           IsPlaceholderUrl(net::GURLWithNSURL(webView.URL))));
+
   NSString* authMethod = challenge.protectionSpace.authenticationMethod;
   if ([authMethod isEqual:NSURLAuthenticationMethodHTTPBasic] ||
       [authMethod isEqual:NSURLAuthenticationMethodNTLM] ||
diff --git a/ios/web/web_state/ui/crw_web_controller_unittest.mm b/ios/web/web_state/ui/crw_web_controller_unittest.mm
index 0d0cc9c..cd10050 100644
--- a/ios/web/web_state/ui/crw_web_controller_unittest.mm
+++ b/ios/web/web_state/ui/crw_web_controller_unittest.mm
@@ -1022,5 +1022,4 @@
   [web_state_->GetWebController() loadCurrentURLIfNecessary];
   EXPECT_TRUE(test::WaitForWebViewContainingText(web_state_.get(), "pony"));
 };
-
 }  // namespace web
diff --git a/ipc/ipc_channel_mojo.cc b/ipc/ipc_channel_mojo.cc
index 38d07cc..29451c6 100644
--- a/ipc/ipc_channel_mojo.cc
+++ b/ipc/ipc_channel_mojo.cc
@@ -29,6 +29,7 @@
 #include "mojo/public/cpp/system/platform_handle.h"
 
 #if defined(OS_POSIX)
+#include "base/posix/eintr_wrapper.h"
 #include "ipc/ipc_platform_file_attachment_posix.h"
 #endif
 
@@ -134,8 +135,9 @@
 
 #if defined(OS_POSIX)
 base::ScopedFD TakeOrDupFile(internal::PlatformFileAttachment* attachment) {
-  return attachment->Owns() ? base::ScopedFD(attachment->TakePlatformFile())
-                            : base::ScopedFD(dup(attachment->file()));
+  return attachment->Owns()
+             ? base::ScopedFD(attachment->TakePlatformFile())
+             : base::ScopedFD(HANDLE_EINTR(dup(attachment->file())));
 }
 #endif  // defined(OS_POSIX)
 
diff --git a/ipc/ipc_channel_mojo_unittest.cc b/ipc/ipc_channel_mojo_unittest.cc
index 012877c..21a853f 100644
--- a/ipc/ipc_channel_mojo_unittest.cc
+++ b/ipc/ipc_channel_mojo_unittest.cc
@@ -17,6 +17,7 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/location.h"
 #include "base/macros.h"
+#include "base/memory/shared_memory.h"
 #include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
 #include "base/pickle.h"
@@ -30,6 +31,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "ipc/ipc_message.h"
+#include "ipc/ipc_message_utils.h"
 #include "ipc/ipc_mojo_handle_attachment.h"
 #include "ipc/ipc_mojo_message_helper.h"
 #include "ipc/ipc_mojo_param_traits.h"
@@ -62,7 +64,8 @@
 
 class ListenerThatExpectsOK : public IPC::Listener {
  public:
-  ListenerThatExpectsOK() : received_ok_(false) {}
+  ListenerThatExpectsOK(base::Closure quit_closure)
+      : received_ok_(false), quit_closure_(quit_closure) {}
 
   ~ListenerThatExpectsOK() override {}
 
@@ -72,7 +75,7 @@
     EXPECT_TRUE(iter.ReadString(&should_be_ok));
     EXPECT_EQ(should_be_ok, "OK");
     received_ok_ = true;
-    base::RunLoop::QuitCurrentWhenIdleDeprecated();
+    quit_closure_.Run();
     return true;
   }
 
@@ -87,6 +90,24 @@
 
  private:
   bool received_ok_;
+  base::Closure quit_closure_;
+};
+
+class TestListenerBase : public IPC::Listener {
+ public:
+  TestListenerBase(base::Closure quit_closure) : quit_closure_(quit_closure) {}
+
+  ~TestListenerBase() override {}
+
+  void OnChannelError() override { quit_closure_.Run(); }
+
+  void set_sender(IPC::Sender* sender) { sender_ = sender; }
+  IPC::Sender* sender() const { return sender_; }
+  base::Closure quit_closure() const { return quit_closure_; }
+
+ private:
+  IPC::Sender* sender_ = nullptr;
+  base::Closure quit_closure_;
 };
 
 using IPCChannelMojoTest = IPCChannelMojoTestBase;
@@ -144,15 +165,16 @@
   Close();
 }
 
-class ListenerExpectingErrors : public IPC::Listener {
+class ListenerExpectingErrors : public TestListenerBase {
  public:
-  ListenerExpectingErrors() : has_error_(false) {}
+  ListenerExpectingErrors(base::Closure quit_closure)
+      : TestListenerBase(quit_closure), has_error_(false) {}
 
   bool OnMessageReceived(const IPC::Message& message) override { return true; }
 
   void OnChannelError() override {
     has_error_ = true;
-    base::RunLoop::QuitCurrentWhenIdleDeprecated();
+    TestListenerBase::OnChannelError();
   }
 
   bool has_error() const { return has_error_; }
@@ -163,21 +185,23 @@
 
 class ListenerThatQuits : public IPC::Listener {
  public:
-  ListenerThatQuits() {}
+  ListenerThatQuits(base::Closure quit_closure) : quit_closure_(quit_closure) {}
 
   bool OnMessageReceived(const IPC::Message& message) override { return true; }
 
-  void OnChannelConnected(int32_t peer_pid) override {
-    base::RunLoop::QuitCurrentWhenIdleDeprecated();
-  }
+  void OnChannelConnected(int32_t peer_pid) override { quit_closure_.Run(); }
+
+ private:
+  base::Closure quit_closure_;
 };
 
 // A long running process that connects to us.
 DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT(IPCChannelMojoErraticTestClient) {
-  ListenerThatQuits listener;
+  base::RunLoop run_loop;
+  ListenerThatQuits listener(run_loop.QuitClosure());
   Connect(&listener);
 
-  base::RunLoop().Run();
+  run_loop.Run();
 
   Close();
 }
@@ -186,7 +210,8 @@
   Init("IPCChannelMojoErraticTestClient");
 
   // Set up IPC channel and start client.
-  ListenerExpectingErrors listener;
+  base::RunLoop run_loop;
+  ListenerExpectingErrors listener(run_loop.QuitClosure());
   CreateChannel(&listener);
   ASSERT_TRUE(ConnectChannel());
 
@@ -199,7 +224,7 @@
                                              overly_large_data.c_str());
   }
 
-  base::RunLoop().Run();
+  run_loop.Run();
 
   channel()->Close();
 
@@ -286,7 +311,6 @@
 
   static void ReadReceivedFile(const IPC::Message& message,
                                base::PickleIterator* iter) {
-    base::ScopedFD fd;
     scoped_refptr<base::Pickle::Attachment> attachment;
     EXPECT_TRUE(message.ReadAttachment(iter, &attachment));
     EXPECT_EQ(
@@ -302,40 +326,33 @@
 #endif
 };
 
-class ListenerThatExpectsMessagePipe : public IPC::Listener {
+class ListenerThatExpectsMessagePipe : public TestListenerBase {
  public:
-  ListenerThatExpectsMessagePipe() : sender_(NULL) {}
+  ListenerThatExpectsMessagePipe(base::Closure quit_closure)
+      : TestListenerBase(quit_closure) {}
 
   ~ListenerThatExpectsMessagePipe() override {}
 
   bool OnMessageReceived(const IPC::Message& message) override {
     base::PickleIterator iter(message);
     HandleSendingHelper::ReadReceivedPipe(message, &iter);
-    ListenerThatExpectsOK::SendOK(sender_);
+    ListenerThatExpectsOK::SendOK(sender());
     return true;
   }
-
-  void OnChannelError() override {
-    base::RunLoop::QuitCurrentWhenIdleDeprecated();
-  }
-
-  void set_sender(IPC::Sender* sender) { sender_ = sender; }
-
- private:
-  IPC::Sender* sender_;
 };
 
 TEST_F(IPCChannelMojoTest, SendMessagePipe) {
   Init("IPCChannelMojoTestSendMessagePipeClient");
 
-  ListenerThatExpectsOK listener;
+  base::RunLoop run_loop;
+  ListenerThatExpectsOK listener(run_loop.QuitClosure());
   CreateChannel(&listener);
   ASSERT_TRUE(ConnectChannel());
 
   TestingMessagePipe pipe;
   HandleSendingHelper::WritePipeThenSend(channel(), &pipe);
 
-  base::RunLoop().Run();
+  run_loop.Run();
   channel()->Close();
 
   EXPECT_TRUE(WaitForClientShutdown());
@@ -343,11 +360,12 @@
 }
 
 DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT(IPCChannelMojoTestSendMessagePipeClient) {
-  ListenerThatExpectsMessagePipe listener;
+  base::RunLoop run_loop;
+  ListenerThatExpectsMessagePipe listener(run_loop.QuitClosure());
   Connect(&listener);
   listener.set_sender(channel());
 
-  base::RunLoop().Run();
+  run_loop.Run();
 
   Close();
 }
@@ -367,10 +385,12 @@
                                  nullptr, 0, 0));
 }
 
-class ListenerThatExpectsMessagePipeUsingParamTrait : public IPC::Listener {
+class ListenerThatExpectsMessagePipeUsingParamTrait : public TestListenerBase {
  public:
-  explicit ListenerThatExpectsMessagePipeUsingParamTrait(bool receiving_valid)
-      : sender_(NULL), receiving_valid_(receiving_valid) {}
+  explicit ListenerThatExpectsMessagePipeUsingParamTrait(
+      base::Closure quit_closure,
+      bool receiving_valid)
+      : TestListenerBase(quit_closure), receiving_valid_(receiving_valid) {}
 
   ~ListenerThatExpectsMessagePipeUsingParamTrait() override {}
 
@@ -385,30 +405,24 @@
       MojoClose(handle.value());
     }
 
-    ListenerThatExpectsOK::SendOK(sender_);
+    ListenerThatExpectsOK::SendOK(sender());
     return true;
   }
 
-  void OnChannelError() override {
-    base::RunLoop::QuitCurrentWhenIdleDeprecated();
-  }
-
-  void set_sender(IPC::Sender* sender) { sender_ = sender; }
-
  private:
-  IPC::Sender* sender_;
   bool receiving_valid_;
 };
 
 class ParamTraitMessagePipeClient : public IpcChannelMojoTestClient {
  public:
   void RunTest(bool receiving_valid_handle) {
+    base::RunLoop run_loop;
     ListenerThatExpectsMessagePipeUsingParamTrait listener(
-        receiving_valid_handle);
+        run_loop.QuitClosure(), receiving_valid_handle);
     Connect(&listener);
     listener.set_sender(channel());
 
-    base::RunLoop().Run();
+    run_loop.Run();
 
     Close();
   }
@@ -417,7 +431,8 @@
 TEST_F(IPCChannelMojoTest, ParamTraitValidMessagePipe) {
   Init("ParamTraitValidMessagePipeClient");
 
-  ListenerThatExpectsOK listener;
+  base::RunLoop run_loop;
+  ListenerThatExpectsOK listener(run_loop.QuitClosure());
   CreateChannel(&listener);
   ASSERT_TRUE(ConnectChannel());
 
@@ -429,7 +444,7 @@
   WriteOK(pipe.self.get());
 
   channel()->Send(message.release());
-  base::RunLoop().Run();
+  run_loop.Run();
   channel()->Close();
 
   EXPECT_TRUE(WaitForClientShutdown());
@@ -445,7 +460,8 @@
 TEST_F(IPCChannelMojoTest, ParamTraitInvalidMessagePipe) {
   Init("ParamTraitInvalidMessagePipeClient");
 
-  ListenerThatExpectsOK listener;
+  base::RunLoop run_loop;
+  ListenerThatExpectsOK listener(run_loop.QuitClosure());
   CreateChannel(&listener);
   ASSERT_TRUE(ConnectChannel());
 
@@ -455,7 +471,7 @@
                                                    invalid_handle);
 
   channel()->Send(message.release());
-  base::RunLoop().Run();
+  run_loop.Run();
   channel()->Close();
 
   EXPECT_TRUE(WaitForClientShutdown());
@@ -471,11 +487,12 @@
 TEST_F(IPCChannelMojoTest, SendFailAfterClose) {
   Init("IPCChannelMojoTestSendOkClient");
 
-  ListenerThatExpectsOK listener;
+  base::RunLoop run_loop;
+  ListenerThatExpectsOK listener(run_loop.QuitClosure());
   CreateChannel(&listener);
   ASSERT_TRUE(ConnectChannel());
 
-  base::RunLoop().Run();
+  run_loop.Run();
   channel()->Close();
   ASSERT_FALSE(channel()->Send(new IPC::Message()));
 
@@ -483,29 +500,26 @@
   DestroyChannel();
 }
 
-class ListenerSendingOneOk : public IPC::Listener {
+class ListenerSendingOneOk : public TestListenerBase {
  public:
-  ListenerSendingOneOk() {}
+  ListenerSendingOneOk(base::Closure quit_closure)
+      : TestListenerBase(quit_closure) {}
 
   bool OnMessageReceived(const IPC::Message& message) override { return true; }
 
   void OnChannelConnected(int32_t peer_pid) override {
-    ListenerThatExpectsOK::SendOK(sender_);
-    base::RunLoop::QuitCurrentWhenIdleDeprecated();
+    ListenerThatExpectsOK::SendOK(sender());
+    quit_closure().Run();
   }
-
-  void set_sender(IPC::Sender* sender) { sender_ = sender; }
-
- private:
-  IPC::Sender* sender_;
 };
 
 DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT(IPCChannelMojoTestSendOkClient) {
-  ListenerSendingOneOk listener;
+  base::RunLoop run_loop;
+  ListenerSendingOneOk listener(run_loop.QuitClosure());
   Connect(&listener);
   listener.set_sender(channel());
 
-  base::RunLoop().Run();
+  run_loop.Run();
 
   Close();
 }
@@ -1298,35 +1312,91 @@
   DestroyProxy();
 }
 
+#if !defined(OS_MACOSX)
+// TODO(wez): On Mac we need to set up a MachPortBroker before we can transfer
+// Mach ports (which underpin Sharedmemory on Mac) across IPC.
+
+class ListenerThatExpectsSharedMemory : public TestListenerBase {
+ public:
+  ListenerThatExpectsSharedMemory(base::Closure quit_closure)
+      : TestListenerBase(quit_closure) {}
+
+  bool OnMessageReceived(const IPC::Message& message) override {
+    base::PickleIterator iter(message);
+
+    base::SharedMemoryHandle shared_memory;
+    EXPECT_TRUE(IPC::ReadParam(&message, &iter, &shared_memory));
+    EXPECT_TRUE(shared_memory.IsValid());
+    shared_memory.Close();
+
+    ListenerThatExpectsOK::SendOK(sender());
+    return true;
+  }
+};
+
+TEST_F(IPCChannelMojoTest, SendSharedMemory) {
+  Init("IPCChannelMojoTestSendSharedMemoryClient");
+
+  // Create some shared-memory to share.
+  base::SharedMemoryCreateOptions options;
+  options.size = 1004;
+
+  base::SharedMemory shmem;
+  ASSERT_TRUE(shmem.Create(options));
+
+  // Create a success listener, and launch the child process.
+  base::RunLoop run_loop;
+  ListenerThatExpectsOK listener(run_loop.QuitClosure());
+  CreateChannel(&listener);
+  ASSERT_TRUE(ConnectChannel());
+
+  // Send the child process an IPC with |shmem| attached, to verify
+  // that is is correctly wrapped, transferred and unwrapped.
+  IPC::Message* message = new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL);
+  IPC::WriteParam(message, shmem.handle());
+  ASSERT_TRUE(channel()->Send(message));
+
+  run_loop.Run();
+
+  channel()->Close();
+
+  EXPECT_TRUE(WaitForClientShutdown());
+  DestroyChannel();
+}
+
+DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT(IPCChannelMojoTestSendSharedMemoryClient) {
+  base::RunLoop run_loop;
+  ListenerThatExpectsSharedMemory listener(run_loop.QuitClosure());
+  Connect(&listener);
+  listener.set_sender(channel());
+
+  run_loop.Run();
+
+  Close();
+}
+
+#endif  // !defined(OS_MACOSX)
+
 #if defined(OS_POSIX)
 
-class ListenerThatExpectsFile : public IPC::Listener {
+class ListenerThatExpectsFile : public TestListenerBase {
  public:
-  ListenerThatExpectsFile() : sender_(NULL) {}
-
-  ~ListenerThatExpectsFile() override {}
+  ListenerThatExpectsFile(base::Closure quit_closure)
+      : TestListenerBase(quit_closure) {}
 
   bool OnMessageReceived(const IPC::Message& message) override {
     base::PickleIterator iter(message);
     HandleSendingHelper::ReadReceivedFile(message, &iter);
-    ListenerThatExpectsOK::SendOK(sender_);
+    ListenerThatExpectsOK::SendOK(sender());
     return true;
   }
-
-  void OnChannelError() override {
-    base::RunLoop::QuitCurrentWhenIdleDeprecated();
-  }
-
-  void set_sender(IPC::Sender* sender) { sender_ = sender; }
-
- private:
-  IPC::Sender* sender_;
 };
 
-TEST_F(IPCChannelMojoTest, SendPlatformHandle) {
-  Init("IPCChannelMojoTestSendPlatformHandleClient");
+TEST_F(IPCChannelMojoTest, SendPlatformFile) {
+  Init("IPCChannelMojoTestSendPlatformFileClient");
 
-  ListenerThatExpectsOK listener;
+  base::RunLoop run_loop;
+  ListenerThatExpectsOK listener(run_loop.QuitClosure());
   CreateChannel(&listener);
   ASSERT_TRUE(ConnectChannel());
 
@@ -1336,7 +1406,7 @@
                   base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE |
                       base::File::FLAG_READ);
   HandleSendingHelper::WriteFileThenSend(channel(), file);
-  base::RunLoop().Run();
+  run_loop.Run();
 
   channel()->Close();
 
@@ -1344,45 +1414,38 @@
   DestroyChannel();
 }
 
-DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT(
-    IPCChannelMojoTestSendPlatformHandleClient) {
-  ListenerThatExpectsFile listener;
+DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT(IPCChannelMojoTestSendPlatformFileClient) {
+  base::RunLoop run_loop;
+  ListenerThatExpectsFile listener(run_loop.QuitClosure());
   Connect(&listener);
   listener.set_sender(channel());
 
-  base::RunLoop().Run();
+  run_loop.Run();
 
   Close();
 }
 
-class ListenerThatExpectsFileAndPipe : public IPC::Listener {
+class ListenerThatExpectsFileAndMessagePipe : public TestListenerBase {
  public:
-  ListenerThatExpectsFileAndPipe() : sender_(NULL) {}
+  ListenerThatExpectsFileAndMessagePipe(base::Closure quit_closure)
+      : TestListenerBase(quit_closure) {}
 
-  ~ListenerThatExpectsFileAndPipe() override {}
+  ~ListenerThatExpectsFileAndMessagePipe() override {}
 
   bool OnMessageReceived(const IPC::Message& message) override {
     base::PickleIterator iter(message);
     HandleSendingHelper::ReadReceivedFile(message, &iter);
     HandleSendingHelper::ReadReceivedPipe(message, &iter);
-    ListenerThatExpectsOK::SendOK(sender_);
+    ListenerThatExpectsOK::SendOK(sender());
     return true;
   }
-
-  void OnChannelError() override {
-    base::RunLoop::QuitCurrentWhenIdleDeprecated();
-  }
-
-  void set_sender(IPC::Sender* sender) { sender_ = sender; }
-
- private:
-  IPC::Sender* sender_;
 };
 
-TEST_F(IPCChannelMojoTest, SendPlatformHandleAndPipe) {
-  Init("IPCChannelMojoTestSendPlatformHandleAndPipeClient");
+TEST_F(IPCChannelMojoTest, SendPlatformFileAndMessagePipe) {
+  Init("IPCChannelMojoTestSendPlatformFileAndMessagePipeClient");
 
-  ListenerThatExpectsOK listener;
+  base::RunLoop run_loop;
+  ListenerThatExpectsOK listener(run_loop.QuitClosure());
   CreateChannel(&listener);
   ASSERT_TRUE(ConnectChannel());
 
@@ -1394,7 +1457,7 @@
   TestingMessagePipe pipe;
   HandleSendingHelper::WriteFileAndPipeThenSend(channel(), file, &pipe);
 
-  base::RunLoop().Run();
+  run_loop.Run();
   channel()->Close();
 
   EXPECT_TRUE(WaitForClientShutdown());
@@ -1402,12 +1465,13 @@
 }
 
 DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT(
-    IPCChannelMojoTestSendPlatformHandleAndPipeClient) {
-  ListenerThatExpectsFileAndPipe listener;
+    IPCChannelMojoTestSendPlatformFileAndMessagePipeClient) {
+  base::RunLoop run_loop;
+  ListenerThatExpectsFileAndMessagePipe listener(run_loop.QuitClosure());
   Connect(&listener);
   listener.set_sender(channel());
 
-  base::RunLoop().Run();
+  run_loop.Run();
 
   Close();
 }
@@ -1418,11 +1482,14 @@
 
 const base::ProcessId kMagicChildId = 54321;
 
-class ListenerThatVerifiesPeerPid : public IPC::Listener {
+class ListenerThatVerifiesPeerPid : public TestListenerBase {
  public:
+  ListenerThatVerifiesPeerPid(base::Closure quit_closure)
+      : TestListenerBase(quit_closure) {}
+
   void OnChannelConnected(int32_t peer_pid) override {
     EXPECT_EQ(peer_pid, kMagicChildId);
-    base::RunLoop::QuitCurrentWhenIdleDeprecated();
+    quit_closure().Run();
   }
 
   bool OnMessageReceived(const IPC::Message& message) override {
@@ -1434,11 +1501,12 @@
 TEST_F(IPCChannelMojoTest, VerifyGlobalPid) {
   Init("IPCChannelMojoTestVerifyGlobalPidClient");
 
-  ListenerThatVerifiesPeerPid listener;
+  base::RunLoop run_loop;
+  ListenerThatVerifiesPeerPid listener(run_loop.QuitClosure());
   CreateChannel(&listener);
   ASSERT_TRUE(ConnectChannel());
 
-  base::RunLoop().Run();
+  run_loop.Run();
   channel()->Close();
 
   EXPECT_TRUE(WaitForClientShutdown());
@@ -1447,10 +1515,12 @@
 
 DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT(IPCChannelMojoTestVerifyGlobalPidClient) {
   IPC::Channel::SetGlobalPid(kMagicChildId);
-  ListenerThatQuits listener;
+
+  base::RunLoop run_loop;
+  ListenerThatQuits listener(run_loop.QuitClosure());
   Connect(&listener);
 
-  base::RunLoop().Run();
+  run_loop.Run();
 
   Close();
 }
diff --git a/ipc/ipc_message_attachment_set_posix_unittest.cc b/ipc/ipc_message_attachment_set_posix_unittest.cc
index 0bd143df..9fd318a 100644
--- a/ipc/ipc_message_attachment_set_posix_unittest.cc
+++ b/ipc/ipc_message_attachment_set_posix_unittest.cc
@@ -25,7 +25,7 @@
 
 // Returns true if fd was already closed.  Closes fd if not closed.
 bool VerifyClosed(int fd) {
-  const int duped = dup(fd);
+  const int duped = HANDLE_EINTR(dup(fd));
   if (duped != -1) {
     EXPECT_NE(IGNORE_EINTR(close(duped)), -1);
     EXPECT_NE(IGNORE_EINTR(close(fd)), -1);
diff --git a/ipc/ipc_platform_file.cc b/ipc/ipc_platform_file.cc
index db5f8e5..72ed737 100644
--- a/ipc/ipc_platform_file.cc
+++ b/ipc/ipc_platform_file.cc
@@ -7,6 +7,8 @@
 
 #if defined(OS_POSIX)
 #include <unistd.h>
+
+#include "base/posix/eintr_wrapper.h"
 #endif
 
 namespace IPC {
@@ -60,7 +62,7 @@
   // the other process from the I/O thread. Without the dup, calling code might
   // close the source handle before the message is sent, creating a race
   // condition.
-  int fd = close_source_handle ? handle : ::dup(handle);
+  int fd = close_source_handle ? handle : HANDLE_EINTR(::dup(handle));
   return base::FileDescriptor(fd, true);
 #else
   #error Not implemented.
diff --git a/media/audio/audio_output_device.cc b/media/audio/audio_output_device.cc
index b5f4e12..00cfe03 100644
--- a/media/audio/audio_output_device.cc
+++ b/media/audio/audio_output_device.cc
@@ -14,7 +14,6 @@
 #include "base/macros.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/threading/thread_restrictions.h"
-#include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
@@ -179,7 +178,9 @@
 void AudioOutputDevice::RequestDeviceAuthorizationOnIOThread() {
   DCHECK(task_runner()->BelongsToCurrentThread());
   DCHECK_EQ(state_, IDLE);
+
   state_ = AUTHORIZING;
+  auth_start_time_ = base::TimeTicks::Now();
   ipc_->RequestDeviceAuthorization(this, session_id_, device_id_,
                                    security_origin_);
 
@@ -319,6 +320,12 @@
   DCHECK(task_runner()->BelongsToCurrentThread());
 
   auth_timeout_action_.reset();
+  // Times over 15 s should be very rare, so we don't lose interesting data by
+  // making it the upper limit.
+  UMA_HISTOGRAM_CUSTOM_TIMES("Media.Audio.Render.OutputDeviceAuthorizationTime",
+                             base::TimeTicks::Now() - auth_start_time_,
+                             base::TimeDelta::FromMilliseconds(1),
+                             base::TimeDelta::FromSeconds(15), 100);
 
   // Do nothing if late authorization is received after timeout.
   if (state_ == IPC_CLOSED)
diff --git a/media/audio/audio_output_device.h b/media/audio/audio_output_device.h
index af3d11fa..88e1843 100644
--- a/media/audio/audio_output_device.h
+++ b/media/audio/audio_output_device.h
@@ -69,6 +69,7 @@
 #include "base/macros.h"
 #include "base/memory/shared_memory.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/time/time.h"
 #include "media/audio/audio_device_thread.h"
 #include "media/audio/audio_output_ipc.h"
 #include "media/audio/scoped_task_runner_observer.h"
@@ -217,6 +218,9 @@
   const base::TimeDelta auth_timeout_;
   std::unique_ptr<base::OneShotTimer> auth_timeout_action_;
 
+  // Set when authorization starts, for UMA stats.
+  base::TimeTicks auth_start_time_;
+
   DISALLOW_COPY_AND_ASSIGN(AudioOutputDevice);
 };
 
diff --git a/media/base/video_decoder.cc b/media/base/video_decoder.cc
index 9a6de2f..34490bd1 100644
--- a/media/base/video_decoder.cc
+++ b/media/base/video_decoder.cc
@@ -10,6 +10,10 @@
 
 VideoDecoder::VideoDecoder() {}
 
+void VideoDecoder::Destroy() {
+  delete this;
+}
+
 VideoDecoder::~VideoDecoder() {}
 
 bool VideoDecoder::NeedsBitstreamConversion() const {
@@ -25,3 +29,12 @@
 }
 
 }  // namespace media
+
+namespace std {
+
+void default_delete<media::VideoDecoder>::operator()(
+    media::VideoDecoder* ptr) const {
+  ptr->Destroy();
+}
+
+}  // namespace std
diff --git a/media/base/video_decoder.h b/media/base/video_decoder.h
index 30d4ddf..450f20e 100644
--- a/media/base/video_decoder.h
+++ b/media/base/video_decoder.h
@@ -25,25 +25,19 @@
 class MEDIA_EXPORT VideoDecoder {
  public:
   // Callback for VideoDecoder initialization.
-  typedef base::Callback<void(bool success)> InitCB;
+  using InitCB = base::Callback<void(bool success)>;
 
   // Callback for VideoDecoder to return a decoded frame whenever it becomes
   // available. Only non-EOS frames should be returned via this callback.
-  typedef base::Callback<void(const scoped_refptr<VideoFrame>&)> OutputCB;
+  using OutputCB = base::Callback<void(const scoped_refptr<VideoFrame>&)>;
 
   // Callback type for Decode(). Called after the decoder has completed decoding
   // corresponding DecoderBuffer, indicating that it's ready to accept another
   // buffer to decode.
-  typedef base::Callback<void(DecodeStatus)> DecodeCB;
+  using DecodeCB = base::Callback<void(DecodeStatus)>;
 
   VideoDecoder();
 
-  // Fires any pending callbacks, stops and destroys the decoder.
-  // Note: Since this is a destructor, |this| will be destroyed after this call.
-  // Make sure the callbacks fired from this call doesn't post any task that
-  // depends on |this|.
-  virtual ~VideoDecoder();
-
   // Returns the name of the decoder for logging and decoder selection purposes.
   // This name should be available immediately after construction (e.g. before
   // Initialize() is called). It should also be stable in the sense that the
@@ -116,10 +110,36 @@
   // Returns maximum number of parallel decode requests.
   virtual int GetMaxDecodeRequests() const;
 
+ protected:
+  // Deletion is only allowed via Destroy().
+  virtual ~VideoDecoder();
+
  private:
+  friend struct std::default_delete<VideoDecoder>;
+
+  // Fires any pending callbacks, stops and destroys the decoder.
+  virtual void Destroy();
+
   DISALLOW_COPY_AND_ASSIGN(VideoDecoder);
 };
 
 }  // namespace media
 
+namespace std {
+
+// Specialize std::default_delete to call Destroy().
+template <>
+struct MEDIA_EXPORT default_delete<media::VideoDecoder> {
+  constexpr default_delete() = default;
+
+  template <typename U,
+            typename = typename std::enable_if<
+                std::is_convertible<U*, media::VideoDecoder*>::value>::type>
+  default_delete(const default_delete<U>& d) {}
+
+  void operator()(media::VideoDecoder* ptr) const;
+};
+
+}  // namespace std
+
 #endif  // MEDIA_BASE_VIDEO_DECODER_H_
diff --git a/media/base/video_util.cc b/media/base/video_util.cc
index 1617389..c8d7888d 100644
--- a/media/base/video_util.cc
+++ b/media/base/video_util.cc
@@ -301,6 +301,43 @@
   return result;
 }
 
+gfx::Rect ComputeLetterboxRegionForI420(const gfx::Rect& bounds,
+                                        const gfx::Size& content) {
+  DCHECK_EQ(bounds.x() % 2, 0);
+  DCHECK_EQ(bounds.y() % 2, 0);
+  DCHECK_EQ(bounds.width() % 2, 0);
+  DCHECK_EQ(bounds.height() % 2, 0);
+
+  gfx::Rect result = ComputeLetterboxRegion(bounds, content);
+
+  if (result.x() & 1) {
+    // This is always legal since bounds.x() was even and result.x() must always
+    // be greater or equal to bounds.x().
+    result.set_x(result.x() - 1);
+
+    // The result.x() was nudged to the left, so if the width is odd, it should
+    // be perfectly legal to nudge it up by one to make it even.
+    if (result.width() & 1)
+      result.set_width(result.width() + 1);
+  } else /* if (result.x() is even) */ {
+    if (result.width() & 1)
+      result.set_width(result.width() - 1);
+  }
+
+  if (result.y() & 1) {
+    // These operations are legal for the same reasons mentioned above for
+    // result.x().
+    result.set_y(result.y() - 1);
+    if (result.height() & 1)
+      result.set_height(result.height() + 1);
+  } else /* if (result.y() is even) */ {
+    if (result.height() & 1)
+      result.set_height(result.height() - 1);
+  }
+
+  return result;
+}
+
 gfx::Size ScaleSizeToFitWithinTarget(const gfx::Size& size,
                                      const gfx::Size& target) {
   return ScaleSizeToTarget(size, target, true);
diff --git a/media/base/video_util.h b/media/base/video_util.h
index 9c18cdc..ac255e5 100644
--- a/media/base/video_util.h
+++ b/media/base/video_util.h
@@ -63,6 +63,17 @@
 MEDIA_EXPORT gfx::Rect ComputeLetterboxRegion(const gfx::Rect& bounds,
                                               const gfx::Size& content);
 
+// Same as ComputeLetterboxRegion(), except ensure the result has even-numbered
+// x, y, width, and height. |bounds| must already have even-numbered
+// coordinates, but the |content| size can be anything.
+//
+// This is useful for ensuring content scaled and converted to I420 does not
+// have color distortions around the edges in a letterboxed video frame. Note
+// that, in cases where ComputeLetterboxRegion() would return a 1x1-sized Rect,
+// this function could return either a 0x0-sized Rect or a 2x2-sized Rect.
+MEDIA_EXPORT gfx::Rect ComputeLetterboxRegionForI420(const gfx::Rect& bounds,
+                                                     const gfx::Size& content);
+
 // Return a scaled |size| whose area is less than or equal to |target|, where
 // one of its dimensions is equal to |target|'s.  The aspect ratio of |size| is
 // preserved as closely as possible.  If |size| is empty, the result will be
diff --git a/media/base/video_util_unittest.cc b/media/base/video_util_unittest.cc
index 26ca2c0..5cedbeb 100644
--- a/media/base/video_util_unittest.cc
+++ b/media/base/video_util_unittest.cc
@@ -409,6 +409,31 @@
                                      gfx::Size(0, 0)).IsEmpty());
 }
 
+// Tests the ComputeLetterboxRegionForI420 function.
+TEST_F(VideoUtilTest, ComputeLetterboxRegionForI420) {
+  // Note: These are the same trials as in VideoUtilTest.ComputeLetterboxRegion
+  // above, except that Rect coordinates are nudged into even-numbered values.
+  EXPECT_EQ(gfx::Rect(166, 0, 666, 500),
+            ComputeLetterboxRegionForI420(gfx::Rect(0, 0, 1000, 500),
+                                          gfx::Size(640, 480)));
+  EXPECT_EQ(gfx::Rect(0, 312, 500, 374),
+            ComputeLetterboxRegionForI420(gfx::Rect(0, 0, 500, 1000),
+                                          gfx::Size(640, 480)));
+  EXPECT_EQ(gfx::Rect(54, 0, 890, 500),
+            ComputeLetterboxRegionForI420(gfx::Rect(0, 0, 1000, 500),
+                                          gfx::Size(1920, 1080)));
+  EXPECT_EQ(gfx::Rect(0, 12, 100, 74),
+            ComputeLetterboxRegionForI420(gfx::Rect(0, 0, 100, 100),
+                                          gfx::Size(400, 300)));
+  EXPECT_EQ(
+      gfx::Rect(0, 250000000, 2000000000, 1500000000),
+      ComputeLetterboxRegionForI420(gfx::Rect(0, 0, 2000000000, 2000000000),
+                                    gfx::Size(40000, 30000)));
+  EXPECT_TRUE(ComputeLetterboxRegionForI420(
+                  gfx::Rect(0, 0, 2000000000, 2000000000), gfx::Size(0, 0))
+                  .IsEmpty());
+}
+
 TEST_F(VideoUtilTest, ScaleSizeToEncompassTarget) {
   EXPECT_EQ(gfx::Size(1000, 750),
             ScaleSizeToEncompassTarget(gfx::Size(640, 480),
diff --git a/media/blink/video_decode_stats_reporter.cc b/media/blink/video_decode_stats_reporter.cc
index 3da1696..5cfb269 100644
--- a/media/blink/video_decode_stats_reporter.cc
+++ b/media/blink/video_decode_stats_reporter.cc
@@ -13,8 +13,12 @@
 namespace media {
 
 // TODO(chcunningham): Find some authoritative list of frame rates.
-const int kFrameRateBuckets[] = {5,  10, 20,  25,  30,  40,  50,  60, 70,
-                                 80, 90, 100, 120, 150, 200, 250, 300};
+// Framerates in this list go way beyond typical values to account for changes
+// to playback rate.
+const int kFrameRateBuckets[] = {5,   10,  20,  25,  30,  40,  50,   60,
+                                 70,  80,  90,  100, 120, 150, 200,  250,
+                                 300, 350, 400, 450, 500, 550, 600,  650,
+                                 700, 750, 800, 850, 900, 950, 1000, 1500};
 
 // A mix of width and height dimensions for common and not-so-common resolutions
 // spanning 144p -> 12K.
@@ -374,6 +378,10 @@
       std::upper_bound(std::begin(kFrameRateBuckets),
                        std::end(kFrameRateBuckets), std::round(rounded_fps));
 
+  // If no bucket is larger than |rounded_fps|, just used the last bucket;
+  if (upper_bound == std::end(kFrameRateBuckets))
+    return *(upper_bound - 1);
+
   // Return early if its the first bucket.
   if (upper_bound == std::begin(kFrameRateBuckets))
     return *upper_bound;
diff --git a/media/cdm/BUILD.gn b/media/cdm/BUILD.gn
index 6c2a484..05d5df5 100644
--- a/media/cdm/BUILD.gn
+++ b/media/cdm/BUILD.gn
@@ -72,6 +72,8 @@
       "cdm_adapter_factory.h",
       "cdm_allocator.cc",
       "cdm_allocator.h",
+      "cdm_auxiliary_helper.cc",
+      "cdm_auxiliary_helper.h",
       "cdm_file_adapter.cc",
       "cdm_file_adapter.h",
       "cdm_file_io.cc",
@@ -81,6 +83,8 @@
       "cdm_module.cc",
       "cdm_module.h",
       "cdm_wrapper.h",
+      "output_protection.h",
+      "platform_verification.h",
       "supported_cdm_versions.cc",
       "supported_cdm_versions.h",
     ]
@@ -152,6 +156,8 @@
       "cdm_adapter_unittest.cc",
       "external_clear_key_test_helper.cc",
       "external_clear_key_test_helper.h",
+      "mock_helpers.cc",
+      "mock_helpers.h",
       "simple_cdm_allocator.cc",
       "simple_cdm_allocator.h",
       "simple_cdm_allocator_unittest.cc",
diff --git a/media/cdm/aes_decryptor_unittest.cc b/media/cdm/aes_decryptor_unittest.cc
index 020e80f..c4a72d96 100644
--- a/media/cdm/aes_decryptor_unittest.cc
+++ b/media/cdm/aes_decryptor_unittest.cc
@@ -36,8 +36,10 @@
 #if BUILDFLAG(ENABLE_LIBRARY_CDMS)
 #include "media/cdm/api/content_decryption_module.h"
 #include "media/cdm/cdm_adapter.h"
+#include "media/cdm/cdm_auxiliary_helper.h"
 #include "media/cdm/cdm_file_io.h"
 #include "media/cdm/external_clear_key_test_helper.h"
+#include "media/cdm/mock_helpers.h"
 #include "media/cdm/simple_cdm_allocator.h"
 #endif
 
@@ -282,10 +284,10 @@
       CdmModule::GetInstance()->SetCdmPathForTesting(helper_->LibraryPath());
 
       std::unique_ptr<CdmAllocator> allocator(new SimpleCdmAllocator());
+      std::unique_ptr<CdmAuxiliaryHelper> cdm_helper(
+          new MockCdmAuxiliaryHelper(std::move(allocator)));
       CdmAdapter::Create(
-          helper_->KeySystemName(), cdm_config, std::move(allocator),
-          base::Bind(&AesDecryptorTest::CreateCdmFileIO,
-                     base::Unretained(this)),
+          helper_->KeySystemName(), cdm_config, std::move(cdm_helper),
           base::Bind(&MockCdmClient::OnSessionMessage,
                      base::Unretained(&cdm_client_)),
           base::Bind(&MockCdmClient::OnSessionClosed,
diff --git a/media/cdm/cdm_adapter.cc b/media/cdm/cdm_adapter.cc
index 6feb43b..6b5fb3f 100644
--- a/media/cdm/cdm_adapter.cc
+++ b/media/cdm/cdm_adapter.cc
@@ -26,7 +26,7 @@
 #include "media/base/video_decoder_config.h"
 #include "media/base/video_frame.h"
 #include "media/base/video_types.h"
-#include "media/cdm/cdm_allocator.h"
+#include "media/cdm/cdm_auxiliary_helper.h"
 #include "media/cdm/cdm_file_io.h"
 #include "media/cdm/cdm_helpers.h"
 #include "media/cdm/cdm_module.h"
@@ -382,8 +382,7 @@
 void CdmAdapter::Create(
     const std::string& key_system,
     const CdmConfig& cdm_config,
-    std::unique_ptr<CdmAllocator> allocator,
-    const CreateCdmFileIOCB& create_cdm_file_io_cb,
+    std::unique_ptr<CdmAuxiliaryHelper> helper,
     const SessionMessageCB& session_message_cb,
     const SessionClosedCB& session_closed_cb,
     const SessionKeysChangeCB& session_keys_change_cb,
@@ -396,9 +395,8 @@
   DCHECK(!session_expiration_update_cb.is_null());
 
   scoped_refptr<CdmAdapter> cdm = new CdmAdapter(
-      key_system, cdm_config, std::move(allocator), create_cdm_file_io_cb,
-      session_message_cb, session_closed_cb, session_keys_change_cb,
-      session_expiration_update_cb);
+      key_system, cdm_config, std::move(helper), session_message_cb,
+      session_closed_cb, session_keys_change_cb, session_expiration_update_cb);
 
   // |cdm| ownership passed to the promise.
   cdm->Initialize(base::MakeUnique<CdmInitializedPromise>(cdm_created_cb, cdm));
@@ -407,8 +405,7 @@
 CdmAdapter::CdmAdapter(
     const std::string& key_system,
     const CdmConfig& cdm_config,
-    std::unique_ptr<CdmAllocator> allocator,
-    const CreateCdmFileIOCB& create_cdm_file_io_cb,
+    std::unique_ptr<CdmAuxiliaryHelper> helper,
     const SessionMessageCB& session_message_cb,
     const SessionClosedCB& session_closed_cb,
     const SessionKeysChangeCB& session_keys_change_cb,
@@ -421,8 +418,7 @@
       session_expiration_update_cb_(session_expiration_update_cb),
       audio_samples_per_second_(0),
       audio_channel_layout_(CHANNEL_LAYOUT_NONE),
-      allocator_(std::move(allocator)),
-      create_cdm_file_io_cb_(create_cdm_file_io_cb),
+      helper_(std::move(helper)),
       task_runner_(base::ThreadTaskRunnerHandle::Get()),
       pool_(new AudioBufferMemoryPool()),
       weak_factory_(this) {
@@ -431,7 +427,7 @@
   DCHECK(!session_closed_cb_.is_null());
   DCHECK(!session_keys_change_cb_.is_null());
   DCHECK(!session_expiration_update_cb_.is_null());
-  DCHECK(allocator_);
+  DCHECK(helper_);
 }
 
 CdmAdapter::~CdmAdapter() {}
@@ -719,8 +715,7 @@
 
   cdm::InputBuffer input_buffer;
   std::vector<cdm::SubsampleEntry> subsamples;
-  std::unique_ptr<VideoFrameImpl> video_frame =
-      allocator_->CreateCdmVideoFrame();
+  std::unique_ptr<VideoFrameImpl> video_frame = helper_->CreateCdmVideoFrame();
 
   ToCdmInputBuffer(encrypted, &subsamples, &input_buffer);
   cdm::Status status =
@@ -760,7 +755,7 @@
 
 cdm::Buffer* CdmAdapter::Allocate(uint32_t capacity) {
   DCHECK(task_runner_->BelongsToCurrentThread());
-  return allocator_->CreateCdmBuffer(capacity);
+  return helper_->CreateCdmBuffer(capacity);
 }
 
 void CdmAdapter::SetTimer(int64_t delay_ms, void* context) {
@@ -911,25 +906,82 @@
                                        uint32_t challenge_size) {
   DCHECK(task_runner_->BelongsToCurrentThread());
 
-  // TODO(jrummell): If platform verification is available, use it.
-  NOTIMPLEMENTED();
+  helper_->ChallengePlatform(std::string(service_id, service_id_size),
+                             std::string(challenge, challenge_size),
+                             base::Bind(&CdmAdapter::OnChallengePlatformDone,
+                                        weak_factory_.GetWeakPtr()));
+}
+
+void CdmAdapter::OnChallengePlatformDone(
+    bool success,
+    const std::string& signed_data,
+    const std::string& signed_data_signature,
+    const std::string& platform_key_certificate) {
   cdm::PlatformChallengeResponse platform_challenge_response = {};
+  if (success) {
+    platform_challenge_response.signed_data =
+        reinterpret_cast<const uint8_t*>(signed_data.data());
+    platform_challenge_response.signed_data_length = signed_data.length();
+    platform_challenge_response.signed_data_signature =
+        reinterpret_cast<const uint8_t*>(signed_data_signature.data());
+    platform_challenge_response.signed_data_signature_length =
+        signed_data_signature.length();
+    platform_challenge_response.platform_key_certificate =
+        reinterpret_cast<const uint8_t*>(platform_key_certificate.data());
+    platform_challenge_response.platform_key_certificate_length =
+        platform_key_certificate.length();
+  }
+
   cdm_->OnPlatformChallengeResponse(platform_challenge_response);
 }
 
 void CdmAdapter::EnableOutputProtection(uint32_t desired_protection_mask) {
   DCHECK(task_runner_->BelongsToCurrentThread());
 
-  // TODO(jrummell): If output protection is available, use it.
-  NOTIMPLEMENTED();
+  helper_->EnableProtection(
+      desired_protection_mask,
+      base::BindOnce(&CdmAdapter::OnOutputProtectionRequestMade,
+                     weak_factory_.GetWeakPtr()));
+}
+
+void CdmAdapter::OnOutputProtectionRequestMade(bool /* success */) {
+  // CDM needs to call QueryOutputProtectionStatus() to see if it took effect
+  // or not.
 }
 
 void CdmAdapter::QueryOutputProtectionStatus() {
   DCHECK(task_runner_->BelongsToCurrentThread());
 
-  // TODO(jrummell): If output protection is available, use it.
-  NOTIMPLEMENTED();
-  cdm_->OnQueryOutputProtectionStatus(cdm::kQueryFailed, 0, 0);
+  helper_->QueryStatus(base::Bind(&CdmAdapter::OnOutputProtectionStatus,
+                                  weak_factory_.GetWeakPtr()));
+}
+
+void CdmAdapter::OnOutputProtectionStatus(bool success,
+                                          uint32_t link_mask,
+                                          uint32_t protection_mask) {
+// Verify that the values in |link_mask| and |protection_mask| match what the
+// CDM expects.
+#define ASSERT_ENUM_EQ(media_enum, cdm_enum)                              \
+  static_assert(                                                          \
+      static_cast<int32_t>(media_enum) == static_cast<int32_t>(cdm_enum), \
+      "Mismatched enum: " #media_enum " != " #cdm_enum)
+
+  ASSERT_ENUM_EQ(OutputProtection::LinkTypes::NONE, cdm::kLinkTypeNone);
+  ASSERT_ENUM_EQ(OutputProtection::LinkTypes::UNKNOWN, cdm::kLinkTypeUnknown);
+  ASSERT_ENUM_EQ(OutputProtection::LinkTypes::INTERNAL, cdm::kLinkTypeInternal);
+  ASSERT_ENUM_EQ(OutputProtection::LinkTypes::VGA, cdm::kLinkTypeVGA);
+  ASSERT_ENUM_EQ(OutputProtection::LinkTypes::HDMI, cdm::kLinkTypeHDMI);
+  ASSERT_ENUM_EQ(OutputProtection::LinkTypes::DVI, cdm::kLinkTypeDVI);
+  ASSERT_ENUM_EQ(OutputProtection::LinkTypes::DISPLAYPORT,
+                 cdm::kLinkTypeDisplayPort);
+  ASSERT_ENUM_EQ(OutputProtection::LinkTypes::NETWORK, cdm::kLinkTypeNetwork);
+
+  ASSERT_ENUM_EQ(OutputProtection::ProtectionType::NONE, cdm::kProtectionNone);
+  ASSERT_ENUM_EQ(OutputProtection::ProtectionType::HDCP, cdm::kProtectionHDCP);
+
+  cdm_->OnQueryOutputProtectionStatus(
+      success ? cdm::kQuerySucceeded : cdm::kQueryFailed, link_mask,
+      protection_mask);
 }
 
 void CdmAdapter::OnDeferredInitializationDone(cdm::StreamType stream_type,
@@ -955,7 +1007,7 @@
 cdm::FileIO* CdmAdapter::CreateFileIO(cdm::FileIOClient* client) {
   DCHECK(task_runner_->BelongsToCurrentThread());
 
-  std::unique_ptr<CdmFileIO> file_io = create_cdm_file_io_cb_.Run(client);
+  std::unique_ptr<CdmFileIO> file_io = helper_->CreateCdmFileIO(client);
 
   // The CDM owns the returned object and must call FileIO::Close()
   // to release it.
@@ -963,9 +1015,12 @@
 }
 
 void CdmAdapter::RequestStorageId() {
-  // TODO(jrummell): Implement Storage Id. https://crbug.com/478960.
-  NOTIMPLEMENTED();
-  cdm_->OnStorageId(nullptr, 0);
+  helper_->GetStorageId(
+      base::Bind(&CdmAdapter::OnStorageIdObtained, weak_factory_.GetWeakPtr()));
+}
+
+void CdmAdapter::OnStorageIdObtained(const std::vector<uint8_t>& storage_id) {
+  cdm_->OnStorageId(storage_id.data(), storage_id.size());
 }
 
 bool CdmAdapter::AudioFramesDataToAudioFrames(
diff --git a/media/cdm/cdm_adapter.h b/media/cdm/cdm_adapter.h
index 150d17a..adade99 100644
--- a/media/cdm/cdm_adapter.h
+++ b/media/cdm/cdm_adapter.h
@@ -33,18 +33,9 @@
 namespace media {
 
 class AudioFramesImpl;
-class CdmAllocator;
-class CdmFileIO;
+class CdmAuxiliaryHelper;
 class CdmWrapper;
 
-// Called when the CDM needs a FileIO object from the host to do file IO
-// operations. Returns NULL if a FileIO object cannot be obtained. Once a
-// valid FileIO object is returned, |client| must be valid until
-// FileIO::Close() is called. The CDM can call this method multiple times
-// to operate on different files.
-using CreateCdmFileIOCB =
-    base::Callback<std::unique_ptr<CdmFileIO>(cdm::FileIOClient* client)>;
-
 class MEDIA_EXPORT CdmAdapter : public ContentDecryptionModule,
                                 public CdmContext,
                                 public Decryptor,
@@ -59,8 +50,7 @@
   static void Create(
       const std::string& key_system,
       const CdmConfig& cdm_config,
-      std::unique_ptr<CdmAllocator> allocator,
-      const CreateCdmFileIOCB& create_cdm_file_io_cb,
+      std::unique_ptr<CdmAuxiliaryHelper> helper,
       const SessionMessageCB& session_message_cb,
       const SessionClosedCB& session_closed_cb,
       const SessionKeysChangeCB& session_keys_change_cb,
@@ -175,8 +165,7 @@
  private:
   CdmAdapter(const std::string& key_system,
              const CdmConfig& cdm_config,
-             std::unique_ptr<CdmAllocator> allocator,
-             const CreateCdmFileIOCB& create_cdm_file_io_cb,
+             std::unique_ptr<CdmAuxiliaryHelper> helper,
              const SessionMessageCB& session_message_cb,
              const SessionClosedCB& session_closed_cb,
              const SessionKeysChangeCB& session_keys_change_cb,
@@ -201,6 +190,19 @@
       std::unique_ptr<AudioFramesImpl> audio_frames,
       Decryptor::AudioFrames* result_frames);
 
+  // Callbacks for Platform Verification.
+  void OnChallengePlatformDone(bool success,
+                               const std::string& signed_data,
+                               const std::string& signed_data_signature,
+                               const std::string& platform_key_certificate);
+  void OnStorageIdObtained(const std::vector<uint8_t>& storage_id);
+
+  // Callbacks for OutputProtection.
+  void OnOutputProtectionRequestMade(bool success);
+  void OnOutputProtectionStatus(bool success,
+                                uint32_t link_mask,
+                                uint32_t protection_mask);
+
   // Used to keep track of promises while the CDM is processing the request.
   CdmPromiseAdapter cdm_promise_adapter_;
 
@@ -230,8 +232,8 @@
   int audio_samples_per_second_;
   ChannelLayout audio_channel_layout_;
 
-  std::unique_ptr<CdmAllocator> allocator_;
-  CreateCdmFileIOCB create_cdm_file_io_cb_;
+  // Helper that provides additional functionality for the CDM.
+  std::unique_ptr<CdmAuxiliaryHelper> helper_;
 
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 
diff --git a/media/cdm/cdm_adapter_factory.cc b/media/cdm/cdm_adapter_factory.cc
index 48c9ea7..7b7ef7e 100644
--- a/media/cdm/cdm_adapter_factory.cc
+++ b/media/cdm/cdm_adapter_factory.cc
@@ -12,9 +12,9 @@
 namespace media {
 
 CdmAdapterFactory::CdmAdapterFactory(
-    CdmAllocator::CreationCB allocator_creation_cb)
-    : allocator_creation_cb_(std::move(allocator_creation_cb)) {
-  DCHECK(allocator_creation_cb_);
+    CdmAuxiliaryHelper::CreationCB helper_creation_cb)
+    : helper_creation_cb_(std::move(helper_creation_cb)) {
+  DCHECK(helper_creation_cb_);
 }
 
 CdmAdapterFactory::~CdmAdapterFactory() {}
@@ -37,18 +37,16 @@
     return;
   }
 
-  std::unique_ptr<CdmAllocator> cdm_allocator = allocator_creation_cb_.Run();
-  if (!cdm_allocator) {
+  std::unique_ptr<CdmAuxiliaryHelper> cdm_helper = helper_creation_cb_.Run();
+  if (!cdm_helper) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
-        base::Bind(cdm_created_cb, nullptr, "CDM allocator creation failed."));
+        base::Bind(cdm_created_cb, nullptr, "CDM helper creation failed."));
     return;
   }
 
-  // TODO(xhwang): Hook up auxiliary services, e.g. File IO, output protection,
-  // and platform verification.
-  CdmAdapter::Create(key_system, cdm_config, std::move(cdm_allocator),
-                     CreateCdmFileIOCB(), session_message_cb, session_closed_cb,
+  CdmAdapter::Create(key_system, cdm_config, std::move(cdm_helper),
+                     session_message_cb, session_closed_cb,
                      session_keys_change_cb, session_expiration_update_cb,
                      cdm_created_cb);
 }
diff --git a/media/cdm/cdm_adapter_factory.h b/media/cdm/cdm_adapter_factory.h
index f23cb69..cc0d498a0 100644
--- a/media/cdm/cdm_adapter_factory.h
+++ b/media/cdm/cdm_adapter_factory.h
@@ -8,13 +8,13 @@
 #include "base/macros.h"
 #include "media/base/cdm_factory.h"
 #include "media/base/media_export.h"
-#include "media/cdm/cdm_allocator.h"
+#include "media/cdm/cdm_auxiliary_helper.h"
 
 namespace media {
 
 class MEDIA_EXPORT CdmAdapterFactory final : public CdmFactory {
  public:
-  explicit CdmAdapterFactory(CdmAllocator::CreationCB allocator_creation_cb);
+  explicit CdmAdapterFactory(CdmAuxiliaryHelper::CreationCB helper_creation_cb);
   ~CdmAdapterFactory() override;
 
   // CdmFactory implementation.
@@ -28,8 +28,8 @@
               const CdmCreatedCB& cdm_created_cb) override;
 
  private:
-  // Callback to create CdmAllocator for the created CDM.
-  CdmAllocator::CreationCB allocator_creation_cb_;
+  // Callback to create CdmAuxiliaryHelper for the created CDM.
+  CdmAuxiliaryHelper::CreationCB helper_creation_cb_;
 
   DISALLOW_COPY_AND_ASSIGN(CdmAdapterFactory);
 };
diff --git a/media/cdm/cdm_adapter_unittest.cc b/media/cdm/cdm_adapter_unittest.cc
index eb159b3..9ff40feb 100644
--- a/media/cdm/cdm_adapter_unittest.cc
+++ b/media/cdm/cdm_adapter_unittest.cc
@@ -21,6 +21,7 @@
 #include "media/cdm/cdm_file_io.h"
 #include "media/cdm/cdm_module.h"
 #include "media/cdm/external_clear_key_test_helper.h"
+#include "media/cdm/mock_helpers.h"
 #include "media/cdm/simple_cdm_allocator.h"
 #include "media/media_features.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -105,19 +106,20 @@
   void InitializeAndExpect(ExpectedResult expected_result) {
     CdmConfig cdm_config;  // default settings of false are sufficient.
     std::unique_ptr<CdmAllocator> allocator(new SimpleCdmAllocator());
-    CdmAdapter::Create(
-        helper_.KeySystemName(), cdm_config, std::move(allocator),
-        base::Bind(&CdmAdapterTest::CreateCdmFileIO, base::Unretained(this)),
-        base::Bind(&MockCdmClient::OnSessionMessage,
-                   base::Unretained(&cdm_client_)),
-        base::Bind(&MockCdmClient::OnSessionClosed,
-                   base::Unretained(&cdm_client_)),
-        base::Bind(&MockCdmClient::OnSessionKeysChange,
-                   base::Unretained(&cdm_client_)),
-        base::Bind(&MockCdmClient::OnSessionExpirationUpdate,
-                   base::Unretained(&cdm_client_)),
-        base::Bind(&CdmAdapterTest::OnCdmCreated, base::Unretained(this),
-                   expected_result));
+    std::unique_ptr<CdmAuxiliaryHelper> cdm_helper(
+        new MockCdmAuxiliaryHelper(std::move(allocator)));
+    CdmAdapter::Create(helper_.KeySystemName(), cdm_config,
+                       std::move(cdm_helper),
+                       base::Bind(&MockCdmClient::OnSessionMessage,
+                                  base::Unretained(&cdm_client_)),
+                       base::Bind(&MockCdmClient::OnSessionClosed,
+                                  base::Unretained(&cdm_client_)),
+                       base::Bind(&MockCdmClient::OnSessionKeysChange,
+                                  base::Unretained(&cdm_client_)),
+                       base::Bind(&MockCdmClient::OnSessionExpirationUpdate,
+                                  base::Unretained(&cdm_client_)),
+                       base::Bind(&CdmAdapterTest::OnCdmCreated,
+                                  base::Unretained(this), expected_result));
     RunUntilIdle();
   }
 
@@ -228,11 +230,6 @@
 
   void RunUntilIdle() { base::RunLoop().RunUntilIdle(); }
 
-  std::unique_ptr<CdmFileIO> CreateCdmFileIO(cdm::FileIOClient* client) {
-    ADD_FAILURE() << "Should never be called";
-    return nullptr;
-  }
-
   // Methods used for promise resolved/rejected.
   MOCK_METHOD0(OnResolve, void());
   MOCK_METHOD1(OnResolveWithSession, void(const std::string& session_id));
diff --git a/media/cdm/cdm_auxiliary_helper.cc b/media/cdm/cdm_auxiliary_helper.cc
new file mode 100644
index 0000000..09c19832
--- /dev/null
+++ b/media/cdm/cdm_auxiliary_helper.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 "media/cdm/cdm_auxiliary_helper.h"
+
+#include "media/cdm/cdm_helpers.h"
+
+namespace media {
+
+CdmAuxiliaryHelper::CdmAuxiliaryHelper() {}
+CdmAuxiliaryHelper::~CdmAuxiliaryHelper() {}
+
+std::unique_ptr<CdmFileIO> CdmAuxiliaryHelper::CreateCdmFileIO(
+    cdm::FileIOClient* client) {
+  return nullptr;
+}
+
+cdm::Buffer* CdmAuxiliaryHelper::CreateCdmBuffer(size_t capacity) {
+  return nullptr;
+}
+
+std::unique_ptr<VideoFrameImpl> CdmAuxiliaryHelper::CreateCdmVideoFrame() {
+  return nullptr;
+}
+
+void CdmAuxiliaryHelper::QueryStatus(QueryStatusCB callback) {
+  std::move(callback).Run(false, 0, 0);
+}
+
+void CdmAuxiliaryHelper::EnableProtection(uint32_t desired_protection_mask,
+                                          EnableProtectionCB callback) {
+  std::move(callback).Run(false);
+}
+
+void CdmAuxiliaryHelper::ChallengePlatform(const std::string& service_id,
+                                           const std::string& challenge,
+                                           ChallengePlatformCB callback) {
+  std::move(callback).Run(false, "", "", "");
+}
+
+void CdmAuxiliaryHelper::GetStorageId(StorageIdCB callback) {
+  std::move(callback).Run(std::vector<uint8_t>());
+}
+
+}  // namespace media
diff --git a/media/cdm/cdm_auxiliary_helper.h b/media/cdm/cdm_auxiliary_helper.h
new file mode 100644
index 0000000..8b5a741
--- /dev/null
+++ b/media/cdm/cdm_auxiliary_helper.h
@@ -0,0 +1,63 @@
+// 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 MEDIA_CDM_CDM_AUXILIARY_HELPER_H_
+#define MEDIA_CDM_CDM_AUXILIARY_HELPER_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "media/base/media_export.h"
+#include "media/cdm/cdm_allocator.h"
+#include "media/cdm/cdm_file_io.h"
+#include "media/cdm/output_protection.h"
+#include "media/cdm/platform_verification.h"
+
+namespace media {
+
+// Provides a wrapper on the auxiliary functions (CdmAllocator, CdmFileIO,
+// OutputProtection, PlatformVerification) needed by the CDM. The default
+// implementation does nothing -- it simply returns NULL, false, 0, etc.
+// as required to meet the interface.
+class MEDIA_EXPORT CdmAuxiliaryHelper : public CdmAllocator,
+                                        public OutputProtection,
+                                        public PlatformVerification {
+ public:
+  // Callback to create CdmAllocator for the created CDM.
+  using CreationCB =
+      base::RepeatingCallback<std::unique_ptr<CdmAuxiliaryHelper>()>;
+
+  CdmAuxiliaryHelper();
+  ~CdmAuxiliaryHelper() override;
+
+  // Given |client|, create a CdmFileIO object and return it. Caller owns the
+  // returned object, and should only destroy it after Close() has been called.
+  virtual std::unique_ptr<CdmFileIO> CreateCdmFileIO(cdm::FileIOClient* client);
+
+  // CdmAllocator implementation.
+  cdm::Buffer* CreateCdmBuffer(size_t capacity) override;
+  std::unique_ptr<VideoFrameImpl> CreateCdmVideoFrame() override;
+
+  // OutputProtection implementation.
+  void QueryStatus(QueryStatusCB callback) override;
+  void EnableProtection(uint32_t desired_protection_mask,
+                        EnableProtectionCB callback) override;
+
+  // PlatformVerification implementation.
+  void ChallengePlatform(const std::string& service_id,
+                         const std::string& challenge,
+                         ChallengePlatformCB callback) override;
+  void GetStorageId(StorageIdCB callback) override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CdmAuxiliaryHelper);
+};
+
+}  // namespace media
+
+#endif  // MEDIA_CDM_CDM_AUXILIARY_HELPER_H_
diff --git a/media/cdm/mock_helpers.cc b/media/cdm/mock_helpers.cc
new file mode 100644
index 0000000..99625e5e
--- /dev/null
+++ b/media/cdm/mock_helpers.cc
@@ -0,0 +1,43 @@
+// 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 "media/cdm/mock_helpers.h"
+
+namespace media {
+
+MockCdmAuxiliaryHelper::MockCdmAuxiliaryHelper(
+    std::unique_ptr<CdmAllocator> allocator)
+    : allocator_(std::move(allocator)) {}
+
+MockCdmAuxiliaryHelper::~MockCdmAuxiliaryHelper() {}
+
+cdm::Buffer* MockCdmAuxiliaryHelper::CreateCdmBuffer(size_t capacity) {
+  return allocator_->CreateCdmBuffer(capacity);
+}
+
+std::unique_ptr<VideoFrameImpl> MockCdmAuxiliaryHelper::CreateCdmVideoFrame() {
+  return allocator_->CreateCdmVideoFrame();
+}
+
+void MockCdmAuxiliaryHelper::QueryStatus(QueryStatusCB callback) {
+  std::move(callback).Run(QueryStatusCalled(), 0, 0);
+}
+
+void MockCdmAuxiliaryHelper::EnableProtection(uint32_t desired_protection_mask,
+                                              EnableProtectionCB callback) {
+  std::move(callback).Run(EnableProtectionCalled(desired_protection_mask));
+}
+
+void MockCdmAuxiliaryHelper::ChallengePlatform(const std::string& service_id,
+                                               const std::string& challenge,
+                                               ChallengePlatformCB callback) {
+  std::move(callback).Run(ChallengePlatformCalled(service_id, challenge), "",
+                          "", "");
+}
+
+void MockCdmAuxiliaryHelper::GetStorageId(StorageIdCB callback) {
+  std::move(callback).Run(GetStorageIdCalled());
+}
+
+}  // namespace media
diff --git a/media/cdm/mock_helpers.h b/media/cdm/mock_helpers.h
new file mode 100644
index 0000000..a6868f9
--- /dev/null
+++ b/media/cdm/mock_helpers.h
@@ -0,0 +1,59 @@
+// 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 MEDIA_CDM_MOCK_HELPERS_H_
+#define MEDIA_CDM_MOCK_HELPERS_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "media/cdm/cdm_allocator.h"
+#include "media/cdm/cdm_auxiliary_helper.h"
+#include "media/cdm/cdm_helpers.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace media {
+
+class MockCdmAuxiliaryHelper : public CdmAuxiliaryHelper {
+ public:
+  MockCdmAuxiliaryHelper(std::unique_ptr<CdmAllocator> allocator);
+  ~MockCdmAuxiliaryHelper() override;
+
+  MOCK_METHOD1(CreateCdmFileIO,
+               std::unique_ptr<CdmFileIO>(cdm::FileIOClient* client));
+
+  cdm::Buffer* CreateCdmBuffer(size_t capacity) override;
+  std::unique_ptr<VideoFrameImpl> CreateCdmVideoFrame() override;
+
+  // Trampoline methods to workaround GMOCK problems with std::unique_ptr<>
+  // parameters.
+  MOCK_METHOD0(QueryStatusCalled, bool());
+  void QueryStatus(QueryStatusCB callback) override;
+
+  MOCK_METHOD1(EnableProtectionCalled, bool(uint32_t desired_protection_mask));
+  void EnableProtection(uint32_t desired_protection_mask,
+                        EnableProtectionCB callback) override;
+
+  MOCK_METHOD2(ChallengePlatformCalled,
+               bool(const std::string& service_id,
+                    const std::string& challenge));
+  void ChallengePlatform(const std::string& service_id,
+                         const std::string& challenge,
+                         ChallengePlatformCB callback) override;
+
+  MOCK_METHOD0(GetStorageIdCalled, std::vector<uint8_t>());
+  void GetStorageId(StorageIdCB callback) override;
+
+ private:
+  std::unique_ptr<CdmAllocator> allocator_;
+  DISALLOW_COPY_AND_ASSIGN(MockCdmAuxiliaryHelper);
+};
+
+}  // namespace media
+
+#endif  // MEDIA_CDM_MOCK_HELPERS_H_
diff --git a/media/cdm/output_protection.h b/media/cdm/output_protection.h
new file mode 100644
index 0000000..d2bdce3
--- /dev/null
+++ b/media/cdm/output_protection.h
@@ -0,0 +1,75 @@
+// 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 MEDIA_CDM_OUTPUT_PROTECTION_H_
+#define MEDIA_CDM_OUTPUT_PROTECTION_H_
+
+#include <stdint.h>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "media/base/media_export.h"
+
+namespace media {
+
+class MEDIA_EXPORT OutputProtection {
+ public:
+  OutputProtection() = default;
+  virtual ~OutputProtection() = default;
+
+  using QueryStatusCB = base::OnceCallback<
+      void(bool success, uint32_t link_mask, uint32_t protection_mask)>;
+  using EnableProtectionCB = base::OnceCallback<void(bool success)>;
+
+  // Connected output link types returned by QueryStatus(). Must match values
+  // in cdm::OutputLinkTypes.
+  enum class LinkTypes {
+    NONE = 0,
+    UNKNOWN = 1,
+    INTERNAL = 2,
+    VGA = 4,
+    HDMI = 8,
+    DVI = 16,
+    DISPLAYPORT = 32,
+    NETWORK = 64,
+  };
+
+  // Supported output protection methods for use with EnableProtection() and
+  // returned by QueryStatus(). Must match values in
+  // cdm::OutputProtectionMethods.
+  enum class ProtectionType {
+    NONE = 0,
+    HDCP = 1,
+  };
+
+  // Queries link status and protection status. Clients need to query status
+  // periodically in order to detect changes. |callback| will be called with
+  // the following values:
+  // - success: Whether the query succeeded. If false, values of |link_mask|
+  //   and |protection_mask| should be ignored.
+  // - link_mask: The type of connected output links, which is a bit-mask of
+  //   the LinkType values.
+  // - protection_mask: The type of enabled protections, which is a bit-mask
+  //   of the ProtectionType values.
+  virtual void QueryStatus(QueryStatusCB callback) = 0;
+
+  // Sets desired protection methods. |desired_protection_mask| is a bit-mask
+  // of ProtectionType values. Calls |callback| when the request has been made.
+  // Users should call QueryStatus() to verify that it was actually applied.
+  // Protections will be disabled if no longer desired by all instances.
+  // |callback| will be called with the following value:
+  // - success: True when the protection request has been made. This may be
+  //   before the protection have actually been applied. False if it failed
+  //   to make the protection request, and in this case there is no need to
+  //   call QueryStatus().
+  virtual void EnableProtection(uint32_t desired_protection_mask,
+                                EnableProtectionCB callback) = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(OutputProtection);
+};
+
+}  // namespace media
+
+#endif  // MEDIA_CDM_OUTPUT_PROTECTION_H_
diff --git a/media/cdm/platform_verification.h b/media/cdm/platform_verification.h
new file mode 100644
index 0000000..f56e2a9
--- /dev/null
+++ b/media/cdm/platform_verification.h
@@ -0,0 +1,58 @@
+// 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 MEDIA_CDM_PLATFORM_VERIFICATION_H_
+#define MEDIA_CDM_PLATFORM_VERIFICATION_H_
+
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "media/base/media_export.h"
+
+namespace media {
+
+class MEDIA_EXPORT PlatformVerification {
+ public:
+  PlatformVerification() = default;
+  virtual ~PlatformVerification() = default;
+
+  using ChallengePlatformCB =
+      base::OnceCallback<void(bool success,
+                              const std::string& signed_data,
+                              const std::string& signed_data_signature,
+                              const std::string& platform_key_certificate)>;
+  using StorageIdCB =
+      base::OnceCallback<void(const std::vector<uint8_t>& storage_id)>;
+
+  // Allows authorized services to verify that the underlying platform is
+  // trusted. An example of a trusted platform is a Chrome OS device in
+  // verified boot mode. This can be used for protected content playback.
+  //
+  // |service_id| is the service ID for the |challenge|. |challenge| is the
+  // challenge data. |callback| will be called with the following values:
+  // - |success|: whether the platform is successfully verified. If true/false
+  //              the following 3 parameters should be non-empty/empty.
+  // - |signed_data|: the data signed by the platform.
+  // - |signed_data_signature|: the signature of the signed data block.
+  // - |platform_key_certificate|: the device specific certificate for the
+  //                               requested service.
+  virtual void ChallengePlatform(const std::string& service_id,
+                                 const std::string& challenge,
+                                 ChallengePlatformCB callback) = 0;
+
+  // Requests the device's Storage Id. |callback| will be called with the
+  // following value:
+  // - |storage_id|: The devices Storage Id. It may be the empty string if it
+  //                 is not supported by the platform.
+  virtual void GetStorageId(StorageIdCB callback) = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PlatformVerification);
+};
+
+}  // namespace media
+
+#endif  // MEDIA_CDM_PLATFORM_VERIFICATION_H_
diff --git a/media/formats/mp4/box_definitions.cc b/media/formats/mp4/box_definitions.cc
index 7e978c2d..01225be0 100644
--- a/media/formats/mp4/box_definitions.cc
+++ b/media/formats/mp4/box_definitions.cc
@@ -374,6 +374,9 @@
            reader->Read4Into8(&duration));
   }
 
+  RCHECK_MEDIA_LOGGED(timescale > 0, reader->media_log(),
+                      "Movie header's timescale must not be 0");
+
   RCHECK(reader->Read4s(&rate) &&
          reader->Read2s(&volume) &&
          reader->SkipBytes(10) &&  // reserved
@@ -1054,6 +1057,10 @@
            reader->Read4(&timescale) && reader->Read4Into8(&duration) &&
            reader->Read2(&language_code));
   }
+
+  RCHECK_MEDIA_LOGGED(timescale > 0, reader->media_log(),
+                      "Track media header's timescale must not be 0");
+
   // ISO 639-2/T language code only uses 15 lower bits, so reset the 16th bit.
   language_code &= 0x7fff;
   // Skip playback quality information
diff --git a/media/formats/mp4/track_run_iterator.cc b/media/formats/mp4/track_run_iterator.cc
index ced8405..fba78c9f 100644
--- a/media/formats/mp4/track_run_iterator.cc
+++ b/media/formats/mp4/track_run_iterator.cc
@@ -67,6 +67,8 @@
 TrackRunInfo::~TrackRunInfo() {}
 
 base::TimeDelta TimeDeltaFromRational(int64_t numer, int64_t denom) {
+  DCHECK_NE(denom, 0);
+
   // To avoid overflow, split the following calculation:
   // (numer * base::Time::kMicrosecondsPerSecond) / denom
   // into:
@@ -212,7 +214,6 @@
   }
 
   // |group_description_index| is 1-based.
-  DCHECK_LE(group_description_index, entries->size());
   return (group_description_index > entries->size())
              ? nullptr
              : &(*entries)[group_description_index - 1];
@@ -326,13 +327,13 @@
       tri.is_audio = (stsd.type == kAudio);
       if (tri.is_audio) {
         RCHECK(!stsd.audio_entries.empty());
-        if (desc_idx > stsd.audio_entries.size())
+        if (desc_idx >= stsd.audio_entries.size())
           desc_idx = 0;
         tri.audio_description = &stsd.audio_entries[desc_idx];
         track_encryption = &tri.audio_description->sinf.info.track_encryption;
       } else {
         RCHECK(!stsd.video_entries.empty());
-        if (desc_idx > stsd.video_entries.size())
+        if (desc_idx >= stsd.video_entries.size())
           desc_idx = 0;
         tri.video_description = &stsd.video_entries[desc_idx];
         track_encryption = &tri.video_description->sinf.info.track_encryption;
diff --git a/media/formats/mpeg/mpeg_audio_stream_parser_base.cc b/media/formats/mpeg/mpeg_audio_stream_parser_base.cc
index 4bba26f7..bc453a24 100644
--- a/media/formats/mpeg/mpeg_audio_stream_parser_base.cc
+++ b/media/formats/mpeg/mpeg_audio_stream_parser_base.cc
@@ -277,12 +277,15 @@
 int MPEGAudioStreamParserBase::ParseID3v1(const uint8_t* data, int size) {
   DVLOG(1) << __func__ << "(" << size << ")";
 
-  if (size < kID3v1Size)
-    return 0;
-
   // TODO(acolwell): Add code to actually validate ID3v1 data and
   // expose it as a metadata text track.
-  return !memcmp(data, "TAG+", 4) ? kID3v1ExtendedSize : kID3v1Size;
+
+  if (size < 4)
+    return 0;
+
+  int needed_size = !memcmp(data, "TAG+", 4) ? kID3v1ExtendedSize : kID3v1Size;
+
+  return (size < needed_size) ? 0 : needed_size;
 }
 
 int MPEGAudioStreamParserBase::ParseID3v2(const uint8_t* data, int size) {
diff --git a/media/gpu/BUILD.gn b/media/gpu/BUILD.gn
index f809b23..33512fb 100644
--- a/media/gpu/BUILD.gn
+++ b/media/gpu/BUILD.gn
@@ -222,9 +222,10 @@
       "surface_texture_gl_owner.cc",
       "surface_texture_gl_owner.h",
     ]
-
-    deps += [ "//media/mojo:features" ]
-
+    deps += [
+      "//media/mojo:features",
+      "//services/service_manager/public/cpp:cpp",
+    ]
     if (enable_webrtc) {
       deps += [ "//third_party/libyuv" ]
       sources += [
@@ -232,7 +233,6 @@
         "android_video_encode_accelerator.h",
       ]
     }
-
     if (enable_media_codec_video_decoder) {
       assert(mojo_media_host == "gpu", "MCVD requires the CDM")
       sources += [
@@ -272,7 +272,10 @@
       deps += [ ":libv4l2_generate_stubs" ]
     }
     if (use_v4l2_codec) {
-      deps += [ "//third_party/libyuv" ]
+      deps += [
+        "//third_party/libyuv",
+        "//ui/ozone",
+      ]
       sources += [
         "generic_v4l2_device.cc",
         "generic_v4l2_device.h",
@@ -490,7 +493,7 @@
       "//base/test:test_support",
       "//gpu:test_support",
       "//media",
-      "//media/base/android:test_support",
+      "//media:test_support",
       "//testing/gmock",
       "//testing/gtest",
     ]
diff --git a/media/gpu/DEPS b/media/gpu/DEPS
index cb7766cf..f0a927f6 100644
--- a/media/gpu/DEPS
+++ b/media/gpu/DEPS
@@ -1,5 +1,6 @@
 # Do NOT add net/ or ui/base without a great reason, they're huge!
 include_rules = [
+  "+services/service_manager/public",
   "+third_party/angle",
   "+third_party/libyuv",
   "+third_party/v4l-utils",
diff --git a/media/gpu/android/media_codec_video_decoder.cc b/media/gpu/android/media_codec_video_decoder.cc
index ff2a196a..32ffaeb 100644
--- a/media/gpu/android/media_codec_video_decoder.cc
+++ b/media/gpu/android/media_codec_video_decoder.cc
@@ -109,7 +109,8 @@
     DeviceInfo* device_info,
     AVDACodecAllocator* codec_allocator,
     std::unique_ptr<AndroidVideoSurfaceChooser> surface_chooser,
-    std::unique_ptr<VideoFrameFactory> video_frame_factory)
+    std::unique_ptr<VideoFrameFactory> video_frame_factory,
+    std::unique_ptr<service_manager::ServiceContextRef> connection_ref)
     : state_(State::kBeforeSurfaceInit),
       lazy_init_pending_(true),
       reset_generation_(0),
@@ -120,11 +121,13 @@
       surface_chooser_(std::move(surface_chooser)),
       video_frame_factory_(std::move(video_frame_factory)),
       device_info_(device_info),
+      connection_ref_(std::move(connection_ref)),
       weak_factory_(this) {
   DVLOG(2) << __func__;
 }
 
 MediaCodecVideoDecoder::~MediaCodecVideoDecoder() {
+  DVLOG(2) << __func__;
   ReleaseCodec();
   // Mojo callbacks require that they're run before destruction.
   if (reset_cb_)
@@ -132,6 +135,11 @@
   codec_allocator_->StopThread(&codec_allocator_adapter_);
 }
 
+void MediaCodecVideoDecoder::Destroy() {
+  DVLOG(2) << __func__;
+  delete this;
+}
+
 void MediaCodecVideoDecoder::Initialize(const VideoDecoderConfig& config,
                                         bool low_delay,
                                         CdmContext* cdm_context,
diff --git a/media/gpu/android/media_codec_video_decoder.h b/media/gpu/android/media_codec_video_decoder.h
index 18c227c..da9eb88 100644
--- a/media/gpu/android/media_codec_video_decoder.h
+++ b/media/gpu/android/media_codec_video_decoder.h
@@ -19,6 +19,7 @@
 #include "media/gpu/android_video_surface_chooser.h"
 #include "media/gpu/avda_codec_allocator.h"
 #include "media/gpu/media_gpu_export.h"
+#include "services/service_manager/public/cpp/service_context_ref.h"
 
 namespace media {
 
@@ -61,8 +62,8 @@
       DeviceInfo* device_info,
       AVDACodecAllocator* codec_allocator,
       std::unique_ptr<AndroidVideoSurfaceChooser> surface_chooser,
-      std::unique_ptr<VideoFrameFactory> video_frame_factory);
-  ~MediaCodecVideoDecoder() override;
+      std::unique_ptr<VideoFrameFactory> video_frame_factory,
+      std::unique_ptr<service_manager::ServiceContextRef> connection_ref);
 
   // VideoDecoder implementation:
   std::string GetDisplayName() const override;
@@ -106,6 +107,10 @@
     kForDestroy,
   };
 
+  // Starts teardown.
+  void Destroy() override;
+  ~MediaCodecVideoDecoder() override;
+
   // Finishes initialization.
   void StartLazyInit();
   void OnVideoFrameFactoryInitialized(
@@ -222,7 +227,7 @@
   AndroidOverlayMojoFactoryCB overlay_factory_cb_;
 
   DeviceInfo* device_info_;
-
+  std::unique_ptr<service_manager::ServiceContextRef> connection_ref_;
   base::WeakPtrFactory<MediaCodecVideoDecoder> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(MediaCodecVideoDecoder);
@@ -230,4 +235,13 @@
 
 }  // namespace media
 
+namespace std {
+
+// Specialize std::default_delete to call Destroy().
+template <>
+struct MEDIA_GPU_EXPORT default_delete<media::MediaCodecVideoDecoder>
+    : public default_delete<media::VideoDecoder> {};
+
+}  // namespace std
+
 #endif  // MEDIA_GPU_ANDROID_MEDIA_CODEC_VIDEO_DECODER_H_
diff --git a/media/gpu/android/media_codec_video_decoder_unittest.cc b/media/gpu/android/media_codec_video_decoder_unittest.cc
index 93cbf37..d2e155386 100644
--- a/media/gpu/android/media_codec_video_decoder_unittest.cc
+++ b/media/gpu/android/media_codec_video_decoder_unittest.cc
@@ -94,7 +94,7 @@
         base::ThreadTaskRunnerHandle::Get(), base::Bind(&GetStubCb),
         base::Bind(&OutputWithReleaseMailboxCb), device_info_.get(),
         codec_allocator_.get(), std::move(surface_chooser),
-        std::move(video_frame_factory));
+        std::move(video_frame_factory), nullptr);
   }
 
   // Just call Initialize(). MCVD will be waiting for a call to Decode() before
diff --git a/media/gpu/android/video_frame_factory_impl.cc b/media/gpu/android/video_frame_factory_impl.cc
index 98a0bfe..3f22dd0 100644
--- a/media/gpu/android/video_frame_factory_impl.cc
+++ b/media/gpu/android/video_frame_factory_impl.cc
@@ -20,7 +20,6 @@
 #include "media/base/video_frame.h"
 #include "media/gpu//android/codec_image.h"
 #include "media/gpu/android/codec_wrapper.h"
-#include "media/gpu/ipc/service/media_gpu_channel_manager.h"
 #include "ui/gl/android/surface_texture.h"
 #include "ui/gl/gl_bindings.h"
 
diff --git a/media/gpu/android/video_frame_factory_impl.h b/media/gpu/android/video_frame_factory_impl.h
index 38ec7a0..f8faebb 100644
--- a/media/gpu/android/video_frame_factory_impl.h
+++ b/media/gpu/android/video_frame_factory_impl.h
@@ -14,7 +14,6 @@
 #include "media/gpu/android/codec_wrapper.h"
 #include "media/gpu/android/video_frame_factory.h"
 #include "media/gpu/gles2_decoder_helper.h"
-#include "media/gpu/ipc/service/media_gpu_channel_manager.h"
 #include "media/gpu/media_gpu_export.h"
 #include "media/gpu/surface_texture_gl_owner.h"
 #include "ui/gl/gl_bindings.h"
diff --git a/media/gpu/generic_v4l2_device.cc b/media/gpu/generic_v4l2_device.cc
index f4b4499..b536e74 100644
--- a/media/gpu/generic_v4l2_device.cc
+++ b/media/gpu/generic_v4l2_device.cc
@@ -25,8 +25,12 @@
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
 #include "media/gpu/generic_v4l2_device.h"
+#include "ui/gfx/native_pixmap.h"
 #include "ui/gl/egl_util.h"
 #include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_image_native_pixmap.h"
+#include "ui/ozone/public/ozone_platform.h"
+#include "ui/ozone/public/surface_factory_ozone.h"
 
 #if defined(USE_LIBV4L2)
 // Auto-generated for dlopen libv4l2 libraries
@@ -275,6 +279,85 @@
   return egl_image;
 }
 
+scoped_refptr<gl::GLImage> GenericV4L2Device::CreateGLImage(
+    const gfx::Size& size,
+    uint32_t fourcc,
+    const std::vector<base::ScopedFD>& dmabuf_fds) {
+  DCHECK(CanCreateEGLImageFrom(fourcc));
+  VideoPixelFormat vf_format = V4L2PixFmtToVideoPixelFormat(fourcc);
+  size_t num_planes = VideoFrame::NumPlanes(vf_format);
+  DCHECK_LE(num_planes, 3u);
+  DCHECK_LE(dmabuf_fds.size(), num_planes);
+
+  gfx::NativePixmapHandle native_pixmap_handle;
+
+  std::vector<base::ScopedFD> duped_fds;
+  for (const auto& fd : dmabuf_fds) {
+    duped_fds.emplace_back(HANDLE_EINTR(dup(fd.get())));
+    if (!duped_fds.back().is_valid()) {
+      PLOG(ERROR) << "Failed duplicating a dmabuf fd";
+      return nullptr;
+    }
+  }
+  for (auto& fd : duped_fds) {
+    native_pixmap_handle.fds.emplace_back(fd.release(), true /* auto_close */);
+  }
+
+  // For existing formats, if we have less buffers (V4L2 planes) than
+  // components (planes), the remaining planes are stored in the last
+  // V4L2 plane. Use one V4L2 plane per each component until we run out of V4L2
+  // planes, and use the last V4L2 plane for all remaining components, each
+  // with an offset equal to the size of the preceding planes in the same
+  // V4L2 plane.
+  size_t v4l2_plane = 0;
+  size_t plane_offset = 0;
+  for (size_t p = 0; p < num_planes; ++p) {
+    native_pixmap_handle.planes.emplace_back(
+        VideoFrame::RowBytes(p, vf_format, size.width()), plane_offset,
+        VideoFrame::PlaneSize(vf_format, p, size).GetArea(), 0);
+
+    if (v4l2_plane + 1 < dmabuf_fds.size()) {
+      ++v4l2_plane;
+      plane_offset = 0;
+    } else {
+      plane_offset += VideoFrame::PlaneSize(vf_format, p, size).GetArea();
+    }
+  }
+
+  gfx::BufferFormat buffer_format = gfx::BufferFormat::BGRA_8888;
+  unsigned internal_format = GL_BGRA_EXT;
+  switch (fourcc) {
+    case DRM_FORMAT_ARGB8888:
+      buffer_format = gfx::BufferFormat::BGRA_8888;
+      internal_format = GL_BGRA_EXT;
+      break;
+    case DRM_FORMAT_NV12:
+      buffer_format = gfx::BufferFormat::YUV_420_BIPLANAR;
+      internal_format = GL_RGB_YCBCR_420V_CHROMIUM;
+      break;
+    case DRM_FORMAT_YVU420:
+      buffer_format = gfx::BufferFormat::YVU_420;
+      internal_format = GL_RGB_YCRCB_420_CHROMIUM;
+      break;
+    default:
+      NOTREACHED();
+  }
+
+  scoped_refptr<gfx::NativePixmap> pixmap =
+      ui::OzonePlatform::GetInstance()
+          ->GetSurfaceFactoryOzone()
+          ->CreateNativePixmapFromHandle(0, size, buffer_format,
+                                         native_pixmap_handle);
+
+  DCHECK(pixmap);
+
+  scoped_refptr<gl::GLImageNativePixmap> image(
+      new gl::GLImageNativePixmap(size, internal_format));
+  bool ret = image->Initialize(pixmap.get(), buffer_format);
+  DCHECK(ret);
+  return image;
+}
+
 EGLBoolean GenericV4L2Device::DestroyEGLImage(EGLDisplay egl_display,
                                               EGLImageKHR egl_image) {
   EGLBoolean result = eglDestroyImageKHR(egl_display, egl_image);
diff --git a/media/gpu/generic_v4l2_device.h b/media/gpu/generic_v4l2_device.h
index 846b5f8..8ef07b6 100644
--- a/media/gpu/generic_v4l2_device.h
+++ b/media/gpu/generic_v4l2_device.h
@@ -51,6 +51,11 @@
       uint32_t v4l2_pixfmt,
       const std::vector<base::ScopedFD>& dmabuf_fds) override;
 
+  scoped_refptr<gl::GLImage> CreateGLImage(
+      const gfx::Size& size,
+      uint32_t fourcc,
+      const std::vector<base::ScopedFD>& dmabuf_fds) override;
+
   EGLBoolean DestroyEGLImage(EGLDisplay egl_display,
                              EGLImageKHR egl_image) override;
   GLenum GetTextureTarget() override;
diff --git a/media/gpu/gpu_video_decode_accelerator_factory.cc b/media/gpu/gpu_video_decode_accelerator_factory.cc
index b440d26..25c4b314 100644
--- a/media/gpu/gpu_video_decode_accelerator_factory.cc
+++ b/media/gpu/gpu_video_decode_accelerator_factory.cc
@@ -216,7 +216,7 @@
   scoped_refptr<V4L2Device> device = V4L2Device::Create();
   if (device.get()) {
     decoder.reset(new V4L2SliceVideoDecodeAccelerator(
-        device, gl::GLSurfaceEGL::GetHardwareDisplay(), get_gl_context_cb_,
+        device, gl::GLSurfaceEGL::GetHardwareDisplay(), bind_image_cb_,
         make_context_current_cb_));
   }
   return decoder;
diff --git a/media/gpu/ipc/service/gpu_video_decode_accelerator.cc b/media/gpu/ipc/service/gpu_video_decode_accelerator.cc
index a64de31..6b65188 100644
--- a/media/gpu/ipc/service/gpu_video_decode_accelerator.cc
+++ b/media/gpu/ipc/service/gpu_video_decode_accelerator.cc
@@ -58,8 +58,6 @@
   return true;
 }
 
-#if (defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)) || \
-    defined(OS_MACOSX) || defined(OS_WIN)
 static bool BindImage(const base::WeakPtr<gpu::GpuCommandBufferStub>& stub,
                       uint32_t client_texture_id,
                       uint32_t texture_target,
@@ -75,7 +73,6 @@
                              can_bind_to_sampler);
   return true;
 }
-#endif
 
 static base::WeakPtr<gpu::gles2::GLES2Decoder> GetGLES2Decoder(
     const base::WeakPtr<gpu::GpuCommandBufferStub>& stub) {
@@ -167,10 +164,7 @@
   get_gl_context_cb_ = base::Bind(&GetGLContext, stub_->AsWeakPtr());
   make_context_current_cb_ =
       base::Bind(&MakeDecoderContextCurrent, stub_->AsWeakPtr());
-#if (defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)) || \
-    defined(OS_MACOSX) || defined(OS_WIN)
   bind_image_cb_ = base::Bind(&BindImage, stub_->AsWeakPtr());
-#endif
   get_gles2_decoder_cb_ = base::Bind(&GetGLES2Decoder, stub_->AsWeakPtr());
 }
 
diff --git a/media/gpu/tegra_v4l2_device.cc b/media/gpu/tegra_v4l2_device.cc
index 7223456..1a6c946 100644
--- a/media/gpu/tegra_v4l2_device.cc
+++ b/media/gpu/tegra_v4l2_device.cc
@@ -213,6 +213,13 @@
   }
   return egl_image;
 }
+scoped_refptr<gl::GLImage> TegraV4L2Device::CreateGLImage(
+    const gfx::Size& size,
+    uint32_t fourcc,
+    const std::vector<base::ScopedFD>& dmabuf_fds) {
+  NOTREACHED();
+  return nullptr;
+}
 
 EGLBoolean TegraV4L2Device::DestroyEGLImage(EGLDisplay egl_display,
                                             EGLImageKHR egl_image) {
diff --git a/media/gpu/tegra_v4l2_device.h b/media/gpu/tegra_v4l2_device.h
index 8529d81a..9d43c8f 100644
--- a/media/gpu/tegra_v4l2_device.h
+++ b/media/gpu/tegra_v4l2_device.h
@@ -49,6 +49,10 @@
       unsigned int buffer_index,
       uint32_t v4l2_pixfmt,
       const std::vector<base::ScopedFD>& dmabuf_fds) override;
+  scoped_refptr<gl::GLImage> CreateGLImage(
+      const gfx::Size& size,
+      uint32_t fourcc,
+      const std::vector<base::ScopedFD>& dmabuf_fds) override;
   EGLBoolean DestroyEGLImage(EGLDisplay egl_display,
                              EGLImageKHR egl_image) override;
   GLenum GetTextureTarget() override;
diff --git a/media/gpu/v4l2_device.h b/media/gpu/v4l2_device.h
index f2f0593..78ea1b9 100644
--- a/media/gpu/v4l2_device.h
+++ b/media/gpu/v4l2_device.h
@@ -23,6 +23,7 @@
 #include "media/video/video_encode_accelerator.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_image.h"
 
 // TODO(posciak): remove this once V4L2 headers are updated.
 #define V4L2_PIX_FMT_MT21 v4l2_fourcc('M', 'T', '2', '1')
@@ -122,6 +123,16 @@
       uint32_t v4l2_pixfmt,
       const std::vector<base::ScopedFD>& dmabuf_fds) = 0;
 
+  // Create a GLImage from provided |dmabuf_fds|.
+  // The caller may choose to close the file descriptors after this method
+  // returns, and may expect the buffers to remain valid for the lifetime of
+  // the created GLImage.
+  // Return the newly created GLImage.
+  virtual scoped_refptr<gl::GLImage> CreateGLImage(
+      const gfx::Size& size,
+      uint32_t fourcc,
+      const std::vector<base::ScopedFD>& dmabuf_fds) = 0;
+
   // Destroys the EGLImageKHR.
   virtual EGLBoolean DestroyEGLImage(EGLDisplay egl_display,
                                      EGLImageKHR egl_image) = 0;
diff --git a/media/gpu/v4l2_slice_video_decode_accelerator.cc b/media/gpu/v4l2_slice_video_decode_accelerator.cc
index 774e7d5..8d0af0c4 100644
--- a/media/gpu/v4l2_slice_video_decode_accelerator.cc
+++ b/media/gpu/v4l2_slice_video_decode_accelerator.cc
@@ -30,6 +30,7 @@
 #include "media/base/media_switches.h"
 #include "media/gpu/shared_memory_region.h"
 #include "ui/gl/gl_context.h"
+#include "ui/gl/gl_image.h"
 #include "ui/gl/scoped_binders.h"
 
 #define LOGF(level) LOG(level) << __func__ << "(): "
@@ -64,6 +65,15 @@
   } while (0)
 
 namespace media {
+namespace {
+void DropGLImage(scoped_refptr<gl::GLImage> gl_image,
+                 BindGLImageCallback bind_image_cb,
+                 GLuint client_texture_id,
+                 GLuint texture_target) {
+  bind_image_cb.Run(client_texture_id, texture_target, nullptr, false);
+}
+
+}  // namespace
 
 // static
 const uint32_t V4L2SliceVideoDecodeAccelerator::supported_input_fourccs_[] = {
@@ -189,7 +199,6 @@
       at_client(false),
       picture_id(-1),
       texture_id(0),
-      egl_image(EGL_NO_IMAGE_KHR),
       egl_sync(EGL_NO_SYNC_KHR),
       cleared(false) {}
 
@@ -459,7 +468,7 @@
 V4L2SliceVideoDecodeAccelerator::V4L2SliceVideoDecodeAccelerator(
     const scoped_refptr<V4L2Device>& device,
     EGLDisplay egl_display,
-    const GetGLContextCallback& get_gl_context_cb,
+    const BindGLImageCallback& bind_image_cb,
     const MakeGLContextCurrentCallback& make_context_current_cb)
     : input_planes_count_(0),
       output_planes_count_(0),
@@ -481,7 +490,7 @@
       surface_set_change_pending_(false),
       picture_clearing_count_(0),
       egl_display_(egl_display),
-      get_gl_context_cb_(get_gl_context_cb),
+      bind_image_cb_(bind_image_cb),
       make_context_current_cb_(make_context_current_cb),
       weak_this_factory_(this) {
   weak_this_ = weak_this_factory_.GetWeakPtr();
@@ -1507,7 +1516,7 @@
   if (output_buffer_map_.empty())
     return true;
 
-  for (const auto& output_record : output_buffer_map_) {
+  for (auto& output_record : output_buffer_map_) {
     DCHECK(!output_record.at_device);
 
     if (output_record.egl_sync != EGL_NO_SYNC_KHR) {
@@ -1515,11 +1524,11 @@
         DVLOGF(1) << "eglDestroySyncKHR failed.";
     }
 
-    if (output_record.egl_image != EGL_NO_IMAGE_KHR) {
+    if (output_record.gl_image) {
       child_task_runner_->PostTask(
-          FROM_HERE,
-          base::Bind(base::IgnoreResult(&V4L2Device::DestroyEGLImage), device_,
-                     egl_display_, output_record.egl_image));
+          FROM_HERE, base::Bind(&DropGLImage, std::move(output_record.gl_image),
+                                bind_image_cb_, output_record.client_texture_id,
+                                device_->GetTextureTarget()));
     }
 
     picture_buffers_to_dismiss.push_back(output_record.picture_id);
@@ -1633,7 +1642,7 @@
     OutputRecord& output_record = output_buffer_map_[i];
     DCHECK(!output_record.at_device);
     DCHECK(!output_record.at_client);
-    DCHECK_EQ(output_record.egl_image, EGL_NO_IMAGE_KHR);
+    DCHECK(!output_record.gl_image);
     DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR);
     DCHECK_EQ(output_record.picture_id, -1);
     DCHECK(output_record.dmabuf_fds.empty());
@@ -1644,6 +1653,10 @@
                                    ? 0
                                    : buffers[i].service_texture_ids()[0];
 
+    output_record.client_texture_id = buffers[i].client_texture_ids().empty()
+                                          ? 0
+                                          : buffers[i].client_texture_ids()[0];
+
     // This will remain true until ImportBufferForPicture is called, either by
     // the client, or by ourselves, if we are allocating.
     output_record.at_client = true;
@@ -1675,10 +1688,11 @@
   ProcessPendingEventsIfNeeded();
 }
 
-void V4L2SliceVideoDecodeAccelerator::CreateEGLImageFor(
+void V4L2SliceVideoDecodeAccelerator::CreateGLImageFor(
     size_t buffer_index,
     int32_t picture_buffer_id,
     std::unique_ptr<std::vector<base::ScopedFD>> passed_dmabuf_fds,
+    GLuint client_texture_id,
     GLuint texture_id,
     const gfx::Size& size,
     uint32_t fourcc) {
@@ -1686,42 +1700,41 @@
   DCHECK(child_task_runner_->BelongsToCurrentThread());
   DCHECK_NE(texture_id, 0u);
 
-  if (get_gl_context_cb_.is_null() || make_context_current_cb_.is_null()) {
-    DLOGF(ERROR) << "GL callbacks required for binding to EGLImages";
+  if (make_context_current_cb_.is_null()) {
+    DLOGF(ERROR) << "GL callbacks required for binding to GLImages";
     NOTIFY_ERROR(INVALID_ARGUMENT);
     return;
   }
-
-  gl::GLContext* gl_context = get_gl_context_cb_.Run();
-  if (!gl_context || !make_context_current_cb_.Run()) {
+  if (!make_context_current_cb_.Run()) {
     DLOGF(ERROR) << "No GL context";
     NOTIFY_ERROR(PLATFORM_FAILURE);
     return;
   }
 
-  gl::ScopedTextureBinder bind_restore(GL_TEXTURE_EXTERNAL_OES, 0);
-
-  EGLImageKHR egl_image =
-      device_->CreateEGLImage(egl_display_, gl_context->GetHandle(), texture_id,
-                              size, buffer_index, fourcc, *passed_dmabuf_fds);
-  if (egl_image == EGL_NO_IMAGE_KHR) {
-    LOGF(ERROR) << "Could not create EGLImageKHR,"
+  scoped_refptr<gl::GLImage> gl_image =
+      device_->CreateGLImage(size, fourcc, *passed_dmabuf_fds);
+  if (!gl_image) {
+    LOGF(ERROR) << "Could not create GLImage,"
                 << " index=" << buffer_index << " texture_id=" << texture_id;
     NOTIFY_ERROR(PLATFORM_FAILURE);
     return;
   }
-
+  gl::ScopedTextureBinder bind_restore(device_->GetTextureTarget(), texture_id);
+  bool ret = gl_image->BindTexImage(device_->GetTextureTarget());
+  DCHECK(ret);
+  bind_image_cb_.Run(client_texture_id, device_->GetTextureTarget(), gl_image,
+                     true);
   decoder_thread_task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(&V4L2SliceVideoDecodeAccelerator::AssignEGLImage,
+      base::Bind(&V4L2SliceVideoDecodeAccelerator::AssignGLImage,
                  base::Unretained(this), buffer_index, picture_buffer_id,
-                 egl_image, base::Passed(&passed_dmabuf_fds)));
+                 gl_image, base::Passed(&passed_dmabuf_fds)));
 }
 
-void V4L2SliceVideoDecodeAccelerator::AssignEGLImage(
+void V4L2SliceVideoDecodeAccelerator::AssignGLImage(
     size_t buffer_index,
     int32_t picture_buffer_id,
-    EGLImageKHR egl_image,
+    scoped_refptr<gl::GLImage> gl_image,
     std::unique_ptr<std::vector<base::ScopedFD>> passed_dmabuf_fds) {
   DVLOGF(3) << "index=" << buffer_index;
   DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread());
@@ -1736,19 +1749,16 @@
   if (buffer_index >= output_buffer_map_.size() ||
       output_buffer_map_[buffer_index].picture_id != picture_buffer_id) {
     DVLOGF(3) << "Picture set already changed, dropping EGLImage";
-    child_task_runner_->PostTask(
-        FROM_HERE, base::Bind(base::IgnoreResult(&V4L2Device::DestroyEGLImage),
-                              device_, egl_display_, egl_image));
     return;
   }
 
   OutputRecord& output_record = output_buffer_map_[buffer_index];
-  DCHECK_EQ(output_record.egl_image, EGL_NO_IMAGE_KHR);
+  DCHECK(!output_record.gl_image);
   DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR);
   DCHECK(!output_record.at_client);
   DCHECK(!output_record.at_device);
 
-  output_record.egl_image = egl_image;
+  output_record.gl_image = gl_image;
   if (output_mode_ == Config::OutputMode::IMPORT) {
     DCHECK(output_record.dmabuf_fds.empty());
     output_record.dmabuf_fds = std::move(*passed_dmabuf_fds);
@@ -1823,21 +1833,15 @@
   DCHECK(!iter->at_device);
   iter->at_client = false;
   if (iter->texture_id != 0) {
-    if (iter->egl_image != EGL_NO_IMAGE_KHR) {
-      child_task_runner_->PostTask(
-          FROM_HERE,
-          base::Bind(base::IgnoreResult(&V4L2Device::DestroyEGLImage), device_,
-                     egl_display_, iter->egl_image));
-    }
-
+    iter->gl_image = nullptr;
     child_task_runner_->PostTask(
         FROM_HERE,
-        base::Bind(&V4L2SliceVideoDecodeAccelerator::CreateEGLImageFor,
+        base::Bind(&V4L2SliceVideoDecodeAccelerator::CreateGLImageFor,
                    weak_this_, index, picture_buffer_id,
-                   base::Passed(&passed_dmabuf_fds), iter->texture_id,
-                   coded_size_, output_format_fourcc_));
+                   base::Passed(&passed_dmabuf_fds), iter->client_texture_id,
+                   iter->texture_id, coded_size_, output_format_fourcc_));
   } else {
-    // No need for an EGLImage, start using this buffer now.
+    // No need for a GLImage, start using this buffer now.
     DCHECK_EQ(output_planes_count_, passed_dmabuf_fds->size());
     iter->dmabuf_fds.swap(*passed_dmabuf_fds);
     free_output_buffers_.push_back(index);
diff --git a/media/gpu/v4l2_slice_video_decode_accelerator.h b/media/gpu/v4l2_slice_video_decode_accelerator.h
index e8634f7c..4bce34a 100644
--- a/media/gpu/v4l2_slice_video_decode_accelerator.h
+++ b/media/gpu/v4l2_slice_video_decode_accelerator.h
@@ -27,6 +27,7 @@
 #include "media/gpu/vp8_decoder.h"
 #include "media/gpu/vp9_decoder.h"
 #include "media/video/video_decode_accelerator.h"
+#include "ui/gl/gl_image.h"
 
 namespace media {
 
@@ -42,7 +43,7 @@
   V4L2SliceVideoDecodeAccelerator(
       const scoped_refptr<V4L2Device>& device,
       EGLDisplay egl_display,
-      const GetGLContextCallback& get_gl_context_cb,
+      const BindGLImageCallback& bind_image_cb,
       const MakeGLContextCurrentCallback& make_context_current_cb);
   ~V4L2SliceVideoDecodeAccelerator() override;
 
@@ -82,11 +83,13 @@
   // Record for output buffers.
   struct OutputRecord {
     OutputRecord();
+    OutputRecord(OutputRecord&&) = default;
     bool at_device;
     bool at_client;
     int32_t picture_id;
+    GLuint client_texture_id;
     GLuint texture_id;
-    EGLImageKHR egl_image;
+    scoped_refptr<gl::GLImage> gl_image;
     EGLSyncKHR egl_sync;
     std::vector<base::ScopedFD> dmabuf_fds;
     bool cleared;
@@ -248,29 +251,29 @@
       // if this method is used as a callback.
       std::unique_ptr<std::vector<base::ScopedFD>> passed_dmabuf_fds);
 
-  // Create an EGLImage for the buffer associated with V4L2 |buffer_index| and
+  // Create a GLImage for the buffer associated with V4L2 |buffer_index| and
   // for |picture_buffer_id|, backed by dmabuf file descriptors in
   // |passed_dmabuf_fds|, taking ownership of them.
-  // The buffer should be bound to |texture_id| and is of |size| and format
-  // described by |fourcc|.
-  void CreateEGLImageFor(
+  // The GLImage will be associated |client_texture_id| in gles2 decoder.
+  void CreateGLImageFor(
       size_t buffer_index,
       int32_t picture_buffer_id,
       // TODO(posciak): (crbug.com/561749) we should normally be able to pass
       // the vector by itself via std::move, but it's not possible to do this
       // if this method is used as a callback.
       std::unique_ptr<std::vector<base::ScopedFD>> passed_dmabuf_fds,
+      GLuint client_texture_id,
       GLuint texture_id,
       const gfx::Size& size,
       uint32_t fourcc);
 
-  // Take the EGLImage |egl_image|, created for |picture_buffer_id|, and use it
+  // Take the GLImage |gl_image|, created for |picture_buffer_id|, and use it
   // for OutputRecord at |buffer_index|. The buffer is backed by
   // |passed_dmabuf_fds|, and the OutputRecord takes ownership of them.
-  void AssignEGLImage(
+  void AssignGLImage(
       size_t buffer_index,
       int32_t picture_buffer_id,
-      EGLImageKHR egl_image,
+      scoped_refptr<gl::GLImage> gl_image,
       // TODO(posciak): (crbug.com/561749) we should normally be able to pass
       // the vector by itself via std::move, but it's not possible to do this
       // if this method is used as a callback.
@@ -465,8 +468,8 @@
   // EGL state
   EGLDisplay egl_display_;
 
-  // Callback to get current GLContext.
-  GetGLContextCallback get_gl_context_cb_;
+  // Callback to bind a GLImage.
+  BindGLImageCallback bind_image_cb_;
   // Callback to set the correct gl context.
   MakeGLContextCurrentCallback make_context_current_cb_;
 
diff --git a/media/mojo/interfaces/BUILD.gn b/media/mojo/interfaces/BUILD.gn
index 9b9bd07..51e8c99 100644
--- a/media/mojo/interfaces/BUILD.gn
+++ b/media/mojo/interfaces/BUILD.gn
@@ -17,6 +17,7 @@
     "media_service.mojom",
     "media_types.mojom",
     "output_protection.mojom",
+    "platform_verification.mojom",
     "provision_fetcher.mojom",
     "renderer.mojom",
     "video_decode_stats_recorder.mojom",
@@ -29,10 +30,6 @@
     sources += [ "media_drm_storage.mojom" ]
   }
 
-  if (is_chromeos) {
-    sources += [ "platform_verification.mojom" ]
-  }
-
   if (is_android) {
     sources += [ "android_overlay.mojom" ]
   }
diff --git a/media/mojo/services/gpu_mojo_media_client.cc b/media/mojo/services/gpu_mojo_media_client.cc
index 8415d241..cec248e 100644
--- a/media/mojo/services/gpu_mojo_media_client.cc
+++ b/media/mojo/services/gpu_mojo_media_client.cc
@@ -82,6 +82,13 @@
 
 GpuMojoMediaClient::~GpuMojoMediaClient() {}
 
+void GpuMojoMediaClient::Initialize(
+    service_manager::Connector* connector,
+    service_manager::ServiceContextRefFactory* context_ref_factory) {
+  DCHECK(context_ref_factory);
+  context_ref_factory_ = context_ref_factory;
+}
+
 std::unique_ptr<AudioDecoder> GpuMojoMediaClient::CreateAudioDecoder(
     scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
 #if defined(OS_ANDROID)
@@ -105,7 +112,8 @@
       AVDACodecAllocator::GetInstance(),
       base::MakeUnique<AndroidVideoSurfaceChooserImpl>(
           DeviceInfo::GetInstance()->IsSetOutputSurfaceSupported()),
-      base::MakeUnique<VideoFrameFactoryImpl>());
+      base::MakeUnique<VideoFrameFactoryImpl>(),
+      context_ref_factory_->CreateRef());
 #else
   return nullptr;
 #endif  // BUILDFLAG(ENABLE_MEDIA_CODEC_VIDEO_DECODER)
diff --git a/media/mojo/services/gpu_mojo_media_client.h b/media/mojo/services/gpu_mojo_media_client.h
index a3c6cb40..075d7d6 100644
--- a/media/mojo/services/gpu_mojo_media_client.h
+++ b/media/mojo/services/gpu_mojo_media_client.h
@@ -27,6 +27,9 @@
   ~GpuMojoMediaClient() final;
 
   // MojoMediaClient implementation.
+  void Initialize(
+      service_manager::Connector* connector,
+      service_manager::ServiceContextRefFactory* context_ref_factory) final;
   std::unique_ptr<AudioDecoder> CreateAudioDecoder(
       scoped_refptr<base::SingleThreadTaskRunner> task_runner) final;
   std::unique_ptr<VideoDecoder> CreateVideoDecoder(
@@ -40,6 +43,7 @@
  private:
   scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner_;
   base::WeakPtr<MediaGpuChannelManager> media_gpu_channel_manager_;
+  service_manager::ServiceContextRefFactory* context_ref_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(GpuMojoMediaClient);
 };
diff --git a/media/mojo/services/media_service.cc b/media/mojo/services/media_service.cc
index c4d17e6..ebe50ca 100644
--- a/media/mojo/services/media_service.cc
+++ b/media/mojo/services/media_service.cc
@@ -29,7 +29,7 @@
   ref_factory_.reset(new service_manager::ServiceContextRefFactory(
       base::Bind(&service_manager::ServiceContext::RequestQuit,
                  base::Unretained(context()))));
-  mojo_media_client_->Initialize(context()->connector());
+  mojo_media_client_->Initialize(context()->connector(), ref_factory_.get());
 }
 
 void MediaService::OnBindInterface(
diff --git a/media/mojo/services/mojo_media_client.cc b/media/mojo/services/mojo_media_client.cc
index 2f2e0818..b163dae 100644
--- a/media/mojo/services/mojo_media_client.cc
+++ b/media/mojo/services/mojo_media_client.cc
@@ -19,7 +19,9 @@
 
 MojoMediaClient::~MojoMediaClient() {}
 
-void MojoMediaClient::Initialize(service_manager::Connector* connector) {}
+void MojoMediaClient::Initialize(
+    service_manager::Connector* connector,
+    service_manager::ServiceContextRefFactory* context_ref_factory) {}
 
 std::unique_ptr<AudioDecoder> MojoMediaClient::CreateAudioDecoder(
     scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
diff --git a/media/mojo/services/mojo_media_client.h b/media/mojo/services/mojo_media_client.h
index d96798f..20ef745 100644
--- a/media/mojo/services/mojo_media_client.h
+++ b/media/mojo/services/mojo_media_client.h
@@ -23,10 +23,11 @@
 
 namespace service_manager {
 class Connector;
+class ServiceContextRefFactory;
 namespace mojom {
 class InterfaceProvider;
 }
-}
+}  // namespace service_manager
 
 namespace media {
 
@@ -54,7 +55,9 @@
 
   // Called exactly once before any other method. |connector| can be used by
   // |this| to connect to other services. It is guaranteed to outlive |this|.
-  virtual void Initialize(service_manager::Connector* connector);
+  virtual void Initialize(
+      service_manager::Connector* connector,
+      service_manager::ServiceContextRefFactory* context_ref_factory);
 
   virtual std::unique_ptr<AudioDecoder> CreateAudioDecoder(
       scoped_refptr<base::SingleThreadTaskRunner> task_runner);
diff --git a/media/mojo/services/mojo_video_decoder_service.h b/media/mojo/services/mojo_video_decoder_service.h
index 93bf6edb..62bf7cbb 100644
--- a/media/mojo/services/mojo_video_decoder_service.h
+++ b/media/mojo/services/mojo_video_decoder_service.h
@@ -12,12 +12,13 @@
 #include "base/memory/weak_ptr.h"
 #include "base/unguessable_token.h"
 #include "media/base/decode_status.h"
+#include "media/base/video_decoder.h"
 #include "media/mojo/interfaces/video_decoder.mojom.h"
 #include "media/mojo/services/mojo_media_client.h"
 
 namespace gpu {
 struct SyncToken;
-};
+}
 
 namespace media {
 
@@ -25,7 +26,6 @@
 class MojoDecoderBufferReader;
 class MojoMediaClient;
 class MojoMediaLog;
-class VideoDecoder;
 class VideoFrame;
 
 // Implementation of a mojom::VideoDecoder which runs in the GPU process,
diff --git a/media/mojo/services/test_mojo_media_client.cc b/media/mojo/services/test_mojo_media_client.cc
index 3836072..ff0ab3b 100644
--- a/media/mojo/services/test_mojo_media_client.cc
+++ b/media/mojo/services/test_mojo_media_client.cc
@@ -35,7 +35,8 @@
 }
 
 void TestMojoMediaClient::Initialize(
-    service_manager::Connector* /* connector */) {
+    service_manager::Connector* /* connector */,
+    service_manager::ServiceContextRefFactory* /* context_ref_factory */) {
   InitializeMediaLibrary();
   // TODO(dalecurtis): We should find a single owner per process for the audio
   // manager or make it a lazy instance.  It's not safe to call Get()/Create()
diff --git a/media/mojo/services/test_mojo_media_client.h b/media/mojo/services/test_mojo_media_client.h
index f593ed8..cd71a86 100644
--- a/media/mojo/services/test_mojo_media_client.h
+++ b/media/mojo/services/test_mojo_media_client.h
@@ -30,7 +30,9 @@
   ~TestMojoMediaClient() final;
 
   // MojoMediaClient implementation.
-  void Initialize(service_manager::Connector* connector) final;
+  void Initialize(
+      service_manager::Connector* connector,
+      service_manager::ServiceContextRefFactory* context_ref_factory) final;
   scoped_refptr<AudioRendererSink> CreateAudioRendererSink(
       const std::string& audio_device_id) final;
   std::unique_ptr<VideoRendererSink> CreateVideoRendererSink(
diff --git a/mojo/edk/system/watcher_dispatcher.cc b/mojo/edk/system/watcher_dispatcher.cc
index db43843..5bd60e5 100644
--- a/mojo/edk/system/watcher_dispatcher.cc
+++ b/mojo/edk/system/watcher_dispatcher.cc
@@ -8,6 +8,7 @@
 #include <limits>
 #include <map>
 
+#include "base/debug/alias.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "mojo/edk/system/watch.h"
@@ -25,6 +26,11 @@
   if (it == watched_handles_.end())
     return;
 
+  // TODO(crbug.com/740044): Remove this.
+  uint32_t sentinel = sentinel_value_for_debugging_;
+  base::debug::Alias(&sentinel);
+  CHECK_EQ(0x12345678u, sentinel);
+
   // Maybe fire a notification to the watch associated with this dispatcher,
   // provided we're armed and it cares about the new state.
   if (it->second->NotifyState(state, armed_)) {
@@ -53,6 +59,11 @@
     watched_handles_.erase(it);
   }
 
+  // TODO(crbug.com/740044): Remove this.
+  uint32_t sentinel = sentinel_value_for_debugging_;
+  base::debug::Alias(&sentinel);
+  CHECK_EQ(0x12345678u, sentinel);
+
   // NOTE: It's important that this is called outside of |lock_| since it
   // acquires internal Watch locks.
   watch->Cancel();
@@ -174,6 +185,11 @@
     watches_.erase(it);
   }
 
+  // TODO(crbug.com/740044): Remove this.
+  uint32_t sentinel = sentinel_value_for_debugging_;
+  base::debug::Alias(&sentinel);
+  CHECK_EQ(0x12345678u, sentinel);
+
   // Mark the watch as cancelled so no further notifications get through.
   watch->Cancel();
 
@@ -253,7 +269,10 @@
   return MOJO_RESULT_FAILED_PRECONDITION;
 }
 
-WatcherDispatcher::~WatcherDispatcher() = default;
+WatcherDispatcher::~WatcherDispatcher() {
+  // TODO(crbug.com/740044): Remove this.
+  sentinel_value_for_debugging_ = 0x87654321;
+}
 
 }  // namespace edk
 }  // namespace mojo
diff --git a/mojo/edk/system/watcher_dispatcher.h b/mojo/edk/system/watcher_dispatcher.h
index 0c5f2552..6a28d294 100644
--- a/mojo/edk/system/watcher_dispatcher.h
+++ b/mojo/edk/system/watcher_dispatcher.h
@@ -5,6 +5,8 @@
 #ifndef MOJO_EDK_SYSTEM_WATCHER_DISPATCHER_H_
 #define MOJO_EDK_SYSTEM_WATCHER_DISPATCHER_H_
 
+#include <stdint.h>
+
 #include <map>
 #include <set>
 
@@ -93,6 +95,9 @@
   // an invalid object. It must therefore never be dereferenced.
   const Watch* last_watch_to_block_arming_ = nullptr;
 
+  // TODO(crbug.com/740044): Remove this.
+  uint32_t sentinel_value_for_debugging_ = 0x12345678;
+
   DISALLOW_COPY_AND_ASSIGN(WatcherDispatcher);
 };
 
diff --git a/mojo/edk/test/test_utils_fuchsia.cc b/mojo/edk/test/test_utils_fuchsia.cc
index ea52d60..5f2d807 100644
--- a/mojo/edk/test/test_utils_fuchsia.cc
+++ b/mojo/edk/test/test_utils_fuchsia.cc
@@ -82,7 +82,7 @@
 
 ScopedPlatformHandle PlatformHandleFromFILE(base::ScopedFILE fp) {
   CHECK(fp);
-  int rv = dup(fileno(fp.get()));
+  int rv = HANDLE_EINTR(dup(fileno(fp.get())));
   PCHECK(rv != -1) << "dup";
   return ScopedPlatformHandle(PlatformHandle::ForFd(rv));
 }
diff --git a/mojo/edk/test/test_utils_posix.cc b/mojo/edk/test/test_utils_posix.cc
index 60d5db5..433c45bc 100644
--- a/mojo/edk/test/test_utils_posix.cc
+++ b/mojo/edk/test/test_utils_posix.cc
@@ -76,7 +76,7 @@
 
 ScopedPlatformHandle PlatformHandleFromFILE(base::ScopedFILE fp) {
   CHECK(fp);
-  int rv = dup(fileno(fp.get()));
+  int rv = HANDLE_EINTR(dup(fileno(fp.get())));
   PCHECK(rv != -1) << "dup";
   return ScopedPlatformHandle(PlatformHandle(rv));
 }
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 85c7ea1..6b12f1b6 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -388,7 +388,6 @@
       "android/cert_verify_result_android.cc",
       "android/cert_verify_result_android.h",
       "android/gurl_utils.cc",
-      "android/gurl_utils.h",
       "android/http_auth_negotiate_android.cc",
       "android/http_auth_negotiate_android.h",
       "android/keystore.cc",
diff --git a/net/android/gurl_utils.cc b/net/android/gurl_utils.cc
index 28a58023..cf0470b 100644
--- a/net/android/gurl_utils.cc
+++ b/net/android/gurl_utils.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "net/android/gurl_utils.h"
-
 #include "base/android/jni_string.h"
 #include "jni/GURLUtils_jni.h"
 #include "url/gurl.h"
@@ -29,8 +27,4 @@
   return base::android::ConvertUTF8ToJavaString(env, host.scheme());
 }
 
-bool RegisterGURLUtils(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
 }  // namespace net
diff --git a/net/android/gurl_utils.h b/net/android/gurl_utils.h
deleted file mode 100644
index 310e42c..0000000
--- a/net/android/gurl_utils.h
+++ /dev/null
@@ -1,16 +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 NET_ANDROID_GURL_UTILS_H_
-#define NET_ANDROID_GURL_UTILS_H_
-
-#include <jni.h>
-
-namespace net {
-
-bool RegisterGURLUtils(JNIEnv* env);
-
-}  // namespace net
-
-#endif  // NET_ANDROID_GURL_UTILS_H_
diff --git a/net/disk_cache/entry_unittest.cc b/net/disk_cache/entry_unittest.cc
index 6f37e598..1f552f42 100644
--- a/net/disk_cache/entry_unittest.cc
+++ b/net/disk_cache/entry_unittest.cc
@@ -9,10 +9,14 @@
 #include "base/files/file.h"
 #include "base/files/file_util.h"
 #include "base/macros.h"
+#include "base/metrics/field_trial.h"
+#include "base/metrics/field_trial_param_associator.h"
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/test/histogram_tester.h"
+#include "base/test/mock_entropy_provider.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/threading/platform_thread.h"
 #include "net/base/completion_callback.h"
 #include "net/base/io_buffer.h"
@@ -75,7 +79,7 @@
   void UpdateSparseEntry();
   void DoomSparseEntry();
   void PartialSparseEntry();
-  bool SimpleCacheMakeBadChecksumEntry(const std::string& key, int* data_size);
+  bool SimpleCacheMakeBadChecksumEntry(const std::string& key, int data_size);
   bool SimpleCacheThirdStreamFileExists(const char* key);
   void SyncDoomEntry(const char* key);
 };
@@ -2632,7 +2636,7 @@
 // Creates an entry with corrupted last byte in stream 0.
 // Requires SimpleCacheMode.
 bool DiskCacheEntryTest::SimpleCacheMakeBadChecksumEntry(const std::string& key,
-                                                         int* data_size) {
+                                                         int data_size) {
   disk_cache::Entry* entry = NULL;
 
   if (CreateEntry(key, &entry) != net::OK || !entry) {
@@ -2640,12 +2644,10 @@
     return false;
   }
 
-  const char data[] = "this is very good data";
-  const int kDataSize = arraysize(data);
-  scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kDataSize));
-  base::strlcpy(buffer->data(), data, kDataSize);
+  scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(data_size));
+  memset(buffer->data(), 'A', data_size);
 
-  EXPECT_EQ(kDataSize, WriteData(entry, 1, 0, buffer.get(), kDataSize, false));
+  EXPECT_EQ(data_size, WriteData(entry, 1, 0, buffer.get(), data_size, false));
   entry->Close();
   entry = NULL;
 
@@ -2658,33 +2660,31 @@
     return false;
 
   int64_t file_offset =
-      sizeof(disk_cache::SimpleFileHeader) + key.size() + kDataSize - 2;
+      sizeof(disk_cache::SimpleFileHeader) + key.size() + data_size - 2;
   EXPECT_EQ(1, entry_file0.Write(file_offset, "X", 1));
-  *data_size = kDataSize;
   return true;
 }
 
-// Tests that the simple cache can detect entries that have bad data.
 TEST_F(DiskCacheEntryTest, SimpleCacheBadChecksum) {
   base::HistogramTester histogram_tester;
   SetSimpleCacheMode();
   InitCache();
 
   const char key[] = "the first key";
-  int size_unused;
-  ASSERT_TRUE(SimpleCacheMakeBadChecksumEntry(key, &size_unused));
+  const int kLargeSize = 50000;
+  ASSERT_TRUE(SimpleCacheMakeBadChecksumEntry(key, kLargeSize));
 
   disk_cache::Entry* entry = NULL;
 
-  // Open the entry.
+  // Open the entry. Can't spot the checksum that quickly with it so
+  // huge.
   ASSERT_THAT(OpenEntry(key, &entry), IsOk());
   ScopedEntryPtr entry_closer(entry);
 
-  const int kReadBufferSize = 200;
-  EXPECT_GE(kReadBufferSize, entry->GetDataSize(1));
-  scoped_refptr<net::IOBuffer> read_buffer(new net::IOBuffer(kReadBufferSize));
+  EXPECT_GE(kLargeSize, entry->GetDataSize(1));
+  scoped_refptr<net::IOBuffer> read_buffer(new net::IOBuffer(kLargeSize));
   EXPECT_EQ(net::ERR_CACHE_CHECKSUM_MISMATCH,
-            ReadData(entry, 1, 0, read_buffer.get(), kReadBufferSize));
+            ReadData(entry, 1, 0, read_buffer.get(), kLargeSize));
   histogram_tester.ExpectUniqueSample(
       "SimpleCache.Http.ReadResult",
       disk_cache::READ_RESULT_SYNC_CHECKSUM_FAILURE, 1);
@@ -2697,8 +2697,8 @@
   InitCache();
 
   const char key[] = "the first key";
-  int size_unused;
-  ASSERT_TRUE(SimpleCacheMakeBadChecksumEntry(key, &size_unused));
+  const int kLargeSize = 50000;
+  ASSERT_TRUE(SimpleCacheMakeBadChecksumEntry(key, kLargeSize));
 
   disk_cache::Entry* entry = NULL;
 
@@ -2706,11 +2706,10 @@
   ASSERT_THAT(OpenEntry(key, &entry), IsOk());
   ScopedEntryPtr entry_closer(entry);
 
-  const int kReadBufferSize = 200;
-  EXPECT_GE(kReadBufferSize, entry->GetDataSize(1));
-  scoped_refptr<net::IOBuffer> read_buffer(new net::IOBuffer(kReadBufferSize));
+  EXPECT_GE(kLargeSize, entry->GetDataSize(1));
+  scoped_refptr<net::IOBuffer> read_buffer(new net::IOBuffer(kLargeSize));
   EXPECT_EQ(net::ERR_CACHE_CHECKSUM_MISMATCH,
-            ReadData(entry, 1, 0, read_buffer.get(), kReadBufferSize));
+            ReadData(entry, 1, 0, read_buffer.get(), kLargeSize));
   histogram_tester.ExpectUniqueSample(
       "SimpleCache.Http.ReadResult",
       disk_cache::READ_RESULT_SYNC_CHECKSUM_FAILURE, 1);
@@ -3446,7 +3445,12 @@
 
   const char key[] = "the first key";
 
-  const int kBufferSize = 1024;
+  // We use a very large entry size here to make sure this doesn't hit
+  // the prefetch path for any concievable setting. Hitting prefetch would
+  // make us serve the read below from memory entirely on I/O thread, missing
+  // the point of the test which coverred two concurrent disk ops, with
+  // portions of work happening on the workpool.
+  const int kBufferSize = 50000;
   scoped_refptr<net::IOBuffer> write_buffer(new net::IOBuffer(kBufferSize));
   CacheTestFillBuffer(write_buffer->data(), kBufferSize, false);
 
@@ -3577,8 +3581,8 @@
   InitCache();
 
   const char key[] = "key";
-  int size;
-  ASSERT_TRUE(SimpleCacheMakeBadChecksumEntry(key, &size));
+  int size = 50000;
+  ASSERT_TRUE(SimpleCacheMakeBadChecksumEntry(key, size));
 
   scoped_refptr<net::IOBuffer> read_buffer1(new net::IOBuffer(size));
   scoped_refptr<net::IOBuffer> read_buffer2(new net::IOBuffer(size));
@@ -4323,3 +4327,210 @@
   ASSERT_THAT(CreateEntry(key, &entry), IsOk());
   entry->Close();
 }
+
+class DiskCacheSimplePrefetchTest : public DiskCacheEntryTest {
+ public:
+  DiskCacheSimplePrefetchTest()
+      : field_trial_list_(base::MakeUnique<base::FieldTrialList>(
+            base::MakeUnique<base::MockEntropyProvider>())) {}
+
+  enum { kEntrySize = 1024 };
+
+  void SetUp() override {
+    payload_ = new net::IOBuffer(kEntrySize);
+    CacheTestFillBuffer(payload_->data(), kEntrySize, false);
+    DiskCacheEntryTest::SetUp();
+  }
+
+  void SetupPrefetch(int size) {
+    std::map<std::string, std::string> params;
+    params[disk_cache::kSimplePrefetchBytesParam] = base::IntToString(size);
+    scoped_feature_list_.InitAndEnableFeatureWithParameters(
+        disk_cache::kSimpleCachePrefetchExperiment, params);
+  }
+
+  void InitCacheAndCreateEntry(const std::string& key) {
+    SetSimpleCacheMode();
+    InitCache();
+
+    disk_cache::Entry* entry;
+    ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+    // Use stream 1 since that's what new prefetch stuff is about.
+    ASSERT_EQ(kEntrySize,
+              WriteData(entry, 1, 0, payload_.get(), kEntrySize, false));
+    entry->Close();
+  }
+
+  void InitCacheAndCreateEntryWithNoCrc(const std::string& key) {
+    const int kHalfSize = kEntrySize / 2;
+    const int kRemSize = kEntrySize - kHalfSize;
+
+    SetSimpleCacheMode();
+    InitCache();
+
+    disk_cache::Entry* entry;
+    ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+    // Use stream 1 since that's what new prefetch stuff is about.
+    ASSERT_EQ(kEntrySize,
+              WriteData(entry, 1, 0, payload_.get(), kEntrySize, false));
+
+    // Overwrite later part of the buffer, since we can't keep track of
+    // the checksum in that case.  Do it with identical contents, though,
+    // so that the only difference between here and InitCacheAndCreateEntry()
+    // would be whether the result has a checkum or not.
+    scoped_refptr<net::IOBuffer> second_half(new net::IOBuffer(kRemSize));
+    memcpy(second_half->data(), payload_->data() + kHalfSize, kRemSize);
+    ASSERT_EQ(kRemSize, WriteData(entry, 1, kHalfSize, second_half.get(),
+                                  kRemSize, false));
+    entry->Close();
+  }
+
+  void TryRead(const std::string& key) {
+    disk_cache::Entry* entry = NULL;
+    ASSERT_THAT(OpenEntry(key, &entry), IsOk());
+    scoped_refptr<net::IOBuffer> read_buf(new net::IOBuffer(kEntrySize));
+    EXPECT_EQ(kEntrySize, ReadData(entry, 1, 0, read_buf.get(), kEntrySize));
+    EXPECT_EQ(0, memcmp(read_buf->data(), payload_->data(), kEntrySize));
+    entry->Close();
+  }
+
+ protected:
+  scoped_refptr<net::IOBuffer> payload_;
+
+  // Need to have the one "global" trial list before we change things.
+  std::unique_ptr<base::FieldTrialList> field_trial_list_;
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+TEST_F(DiskCacheSimplePrefetchTest, NoPrefetch) {
+  base::HistogramTester histogram_tester;
+  SetupPrefetch(0);
+
+  const char kKey[] = "a key";
+  InitCacheAndCreateEntry(kKey);
+  TryRead(kKey);
+
+  histogram_tester.ExpectUniqueSample("SimpleCache.Http.SyncOpenDidPrefetch",
+                                      false, 1);
+  histogram_tester.ExpectUniqueSample(
+      "SimpleCache.Http.ReadStream1FromPrefetched", false, 1);
+}
+
+TEST_F(DiskCacheSimplePrefetchTest, YesPrefetch) {
+  base::HistogramTester histogram_tester;
+  SetupPrefetch(2 * kEntrySize);
+
+  const char kKey[] = "a key";
+  InitCacheAndCreateEntry(kKey);
+  TryRead(kKey);
+
+  histogram_tester.ExpectUniqueSample("SimpleCache.Http.SyncOpenDidPrefetch",
+                                      true, 1);
+  histogram_tester.ExpectUniqueSample(
+      "SimpleCache.Http.ReadStream1FromPrefetched", true, 1);
+}
+
+TEST_F(DiskCacheSimplePrefetchTest, YesPrefetchNoRead) {
+  base::HistogramTester histogram_tester;
+  SetupPrefetch(2 * kEntrySize);
+
+  const char kKey[] = "a key";
+  InitCacheAndCreateEntry(kKey);
+
+  disk_cache::Entry* entry = NULL;
+  ASSERT_THAT(OpenEntry(kKey, &entry), IsOk());
+  entry->Close();
+
+  histogram_tester.ExpectUniqueSample("SimpleCache.Http.SyncOpenDidPrefetch",
+                                      true, 1);
+  // Have to use GetHistogramSamplesSinceCreation here since it's the only
+  // API that handles the cases where the histogram hasn't even been created.
+  std::unique_ptr<base::HistogramSamples> samples(
+      histogram_tester.GetHistogramSamplesSinceCreation(
+          "SimpleCache.Http.ReadStream1FromPrefetched"));
+  EXPECT_EQ(0, samples->TotalCount());
+}
+
+// This makes sure we detect checksum error on entry that's small enough to be
+// prefetched. This is like DiskCacheEntryTest.BadChecksum, but we make sure
+// to configure prefetch explicitly.
+TEST_F(DiskCacheSimplePrefetchTest, BadChecksumSmall) {
+  SetupPrefetch(1024);  // bigger than stuff below.
+  SetSimpleCacheMode();
+  InitCache();
+
+  const char key[] = "the first key";
+  ASSERT_TRUE(SimpleCacheMakeBadChecksumEntry(key, 10));
+
+  disk_cache::Entry* entry = NULL;
+
+  // Open the entry. Since we made a small entry, we will detect the CRC
+  // problem at open.
+  EXPECT_THAT(OpenEntry(key, &entry), IsError(net::ERR_FAILED));
+}
+
+TEST_F(DiskCacheSimplePrefetchTest, ChecksumNoPrefetch) {
+  base::HistogramTester histogram_tester;
+
+  SetupPrefetch(0);
+  const char kKey[] = "a key";
+  InitCacheAndCreateEntry(kKey);
+  TryRead(kKey);
+
+  // Expect 2 CRCs --- stream 0 and stream 1.
+  histogram_tester.ExpectUniqueSample("SimpleCache.Http.SyncCheckEOFHasCrc",
+                                      true, 2);
+  histogram_tester.ExpectUniqueSample("SimpleCache.Http.SyncCheckEOFResult",
+                                      disk_cache::CHECK_EOF_RESULT_SUCCESS, 2);
+}
+
+TEST_F(DiskCacheSimplePrefetchTest, NoChecksumNoPrefetch) {
+  base::HistogramTester histogram_tester;
+
+  SetupPrefetch(0);
+  const char kKey[] = "a key";
+  InitCacheAndCreateEntryWithNoCrc(kKey);
+  TryRead(kKey);
+
+  // Stream 0 has CRC, stream 1 doesn't.
+  histogram_tester.ExpectBucketCount("SimpleCache.Http.SyncCheckEOFHasCrc",
+                                     true, 1);
+  histogram_tester.ExpectBucketCount("SimpleCache.Http.SyncCheckEOFHasCrc",
+                                     false, 1);
+  // EOF check is recorded even if there is no CRC there.
+  histogram_tester.ExpectUniqueSample("SimpleCache.Http.SyncCheckEOFResult",
+                                      disk_cache::CHECK_EOF_RESULT_SUCCESS, 2);
+}
+
+TEST_F(DiskCacheSimplePrefetchTest, ChecksumPrefetch) {
+  base::HistogramTester histogram_tester;
+
+  SetupPrefetch(2 * kEntrySize);
+  const char kKey[] = "a key";
+  InitCacheAndCreateEntry(kKey);
+  TryRead(kKey);
+
+  // Expect 2 CRCs --- stream 0 and stream 1.
+  histogram_tester.ExpectUniqueSample("SimpleCache.Http.SyncCheckEOFHasCrc",
+                                      true, 2);
+  histogram_tester.ExpectUniqueSample("SimpleCache.Http.SyncCheckEOFResult",
+                                      disk_cache::CHECK_EOF_RESULT_SUCCESS, 2);
+}
+
+TEST_F(DiskCacheSimplePrefetchTest, NoChecksumPrefetch) {
+  base::HistogramTester histogram_tester;
+
+  SetupPrefetch(2 * kEntrySize);
+  const char kKey[] = "a key";
+  InitCacheAndCreateEntryWithNoCrc(kKey);
+  TryRead(kKey);
+
+  // Stream 0 has CRC, stream 1 doesn't.
+  histogram_tester.ExpectBucketCount("SimpleCache.Http.SyncCheckEOFHasCrc",
+                                     true, 1);
+  histogram_tester.ExpectBucketCount("SimpleCache.Http.SyncCheckEOFHasCrc",
+                                     false, 1);
+  // EOF check is recorded even if there is no CRC there.
+  histogram_tester.ExpectUniqueSample("SimpleCache.Http.SyncCheckEOFResult",
+                                      disk_cache::CHECK_EOF_RESULT_SUCCESS, 2);
+}
diff --git a/net/disk_cache/simple/simple_entry_impl.cc b/net/disk_cache/simple/simple_entry_impl.cc
index 8ab8e2e..0e860d7 100644
--- a/net/disk_cache/simple/simple_entry_impl.cc
+++ b/net/disk_cache/simple/simple_entry_impl.cc
@@ -179,6 +179,7 @@
       path_(path),
       entry_hash_(entry_hash),
       use_optimistic_operations_(operations_mode == OPTIMISTIC_OPERATIONS),
+      is_initial_stream1_read_(true),
       last_used_(Time::Now()),
       last_modified_(last_used_),
       sparse_data_size_(0),
@@ -550,7 +551,8 @@
   return sizeof(SimpleSynchronousEntry) +
          base::trace_event::EstimateMemoryUsage(pending_operations_) +
          base::trace_event::EstimateMemoryUsage(executing_operation_) +
-         (stream_0_data_ ? stream_0_data_->capacity() : 0);
+         (stream_0_data_ ? stream_0_data_->capacity() : 0) +
+         (stream_1_prefetch_data_ ? stream_1_prefetch_data_->capacity() : 0);
 }
 
 SimpleEntryImpl::~SimpleEntryImpl() {
@@ -851,14 +853,26 @@
 
   // Since stream 0 data is kept in memory, it is read immediately.
   if (stream_index == 0) {
-    int ret_value = ReadStream0Data(buf, offset, buf_len);
-    if (!callback.is_null()) {
-      base::ThreadTaskRunnerHandle::Get()->PostTask(
-          FROM_HERE, base::Bind(callback, ret_value));
-    }
+    ReadFromBufferAndPostReply(stream_0_data_.get(), offset, buf_len, buf,
+                               callback);
     return;
   }
 
+  // Sometimes we can read in-ram prefetched stream 1 data immediately, too.
+  if (stream_index == 1) {
+    if (is_initial_stream1_read_) {
+      SIMPLE_CACHE_UMA(BOOLEAN, "ReadStream1FromPrefetched", cache_type_,
+                       stream_1_prefetch_data_ != nullptr);
+    }
+    is_initial_stream1_read_ = false;
+
+    if (stream_1_prefetch_data_) {
+      ReadFromBufferAndPostReply(stream_1_prefetch_data_.get(), offset, buf_len,
+                                 buf, callback);
+      return;
+    }
+  }
+
   state_ = STATE_IO_PENDING;
   if (!doomed_ && backend_.get())
     backend_->index()->UseIfExists(entry_hash_);
@@ -950,6 +964,10 @@
   if (!doomed_ && backend_.get())
     backend_->index()->UseIfExists(entry_hash_);
 
+  // Any stream 1 write invalidates the prefetched data.
+  if (stream_index == 1)
+    stream_1_prefetch_data_ = nullptr;
+
   AdvanceCrc(buf, offset, buf_len, stream_index);
 
   // |entry_stat| needs to be initialized before modifying |data_size_|.
@@ -1147,13 +1165,24 @@
 
   state_ = STATE_READY;
   synchronous_entry_ = in_results->sync_entry;
-  if (in_results->stream_0_data.get()) {
-    stream_0_data_ = in_results->stream_0_data;
-    // The crc was read in SimpleSynchronousEntry.
-    crc_check_state_[0] = CRC_CHECK_DONE;
-    crc32s_[0] = in_results->stream_0_crc32;
-    crc32s_end_offset_[0] = in_results->entry_stat.data_size(0);
+
+  // Copy over any pre-fetched data and its CRCs.
+  for (int stream = 0; stream < 2; ++stream) {
+    const SimpleStreamPrefetchData& prefetched =
+        in_results->stream_prefetch_data[stream];
+    if (prefetched.data.get()) {
+      if (stream == 0)
+        stream_0_data_ = prefetched.data;
+      else
+        stream_1_prefetch_data_ = prefetched.data;
+
+      // The crc was read in SimpleSynchronousEntry.
+      crc_check_state_[stream] = CRC_CHECK_DONE;
+      crc32s_[stream] = prefetched.stream_crc32;
+      crc32s_end_offset_[stream] = in_results->entry_stat.data_size(stream);
+    }
   }
+
   // If this entry was opened by hash, key_ could still be empty. If so, update
   // it with the key read from the synchronous entry.
   if (key_.empty()) {
@@ -1449,19 +1478,27 @@
                    type, WRITE_DEPENDENCY_TYPE_MAX);
 }
 
-int SimpleEntryImpl::ReadStream0Data(net::IOBuffer* buf,
-                                     int offset,
-                                     int buf_len) {
+void SimpleEntryImpl::ReadFromBufferAndPostReply(
+    net::GrowableIOBuffer* in_buf,
+    int offset,
+    int buf_len,
+    net::IOBuffer* out_buf,
+    const CompletionCallback& callback) {
+  int rv;
   if (buf_len < 0) {
     RecordReadResult(cache_type_, READ_RESULT_SYNC_READ_FAILURE);
-    return 0;
+    rv = 0;
+  } else {
+    memcpy(out_buf->data(), in_buf->data() + offset, buf_len);
+    UpdateDataFromEntryStat(SimpleEntryStat(base::Time::Now(), last_modified_,
+                                            data_size_, sparse_data_size_));
+    RecordReadResult(cache_type_, READ_RESULT_SUCCESS);
+    rv = buf_len;
   }
-  memcpy(buf->data(), stream_0_data_->data() + offset, buf_len);
-  UpdateDataFromEntryStat(
-      SimpleEntryStat(base::Time::Now(), last_modified_, data_size_,
-                      sparse_data_size_));
-  RecordReadResult(cache_type_, READ_RESULT_SUCCESS);
-  return buf_len;
+  if (!callback.is_null()) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                  base::Bind(callback, rv));
+  }
 }
 
 int SimpleEntryImpl::SetStream0Data(net::IOBuffer* buf,
diff --git a/net/disk_cache/simple/simple_entry_impl.h b/net/disk_cache/simple/simple_entry_impl.h
index d9fcc58f..b373c7e 100644
--- a/net/disk_cache/simple/simple_entry_impl.h
+++ b/net/disk_cache/simple/simple_entry_impl.h
@@ -291,9 +291,11 @@
       int result,
       std::unique_ptr<SimpleSynchronousEntry::CRCRequest> crc_result) const;
 
-  // Called after completion of asynchronous IO and receiving file metadata for
-  // the entry in |entry_stat|. Updates the metadata in the entry and in the
-  // index to make them available on next IO operations.
+  // Called after completion of an operation, to either incoproprate file info
+  // received from I/O done on the worker pool, or to simply bump the
+  // timestamps. Updates the metadata both in |this| and in the index.
+  // Stream size information in particular may be important for following
+  // operations.
   void UpdateDataFromEntryStat(const SimpleEntryStat& entry_stat);
 
   int64_t GetDiskUsage() const;
@@ -302,8 +304,14 @@
   void RecordReadIsParallelizable(const SimpleEntryOperation& operation) const;
   void RecordWriteDependencyType(const SimpleEntryOperation& operation) const;
 
-  // Reads from the stream 0 data kept in memory.
-  int ReadStream0Data(net::IOBuffer* buf, int offset, int buf_len);
+  // Completes a read from the stream data kept in memory, logging metrics
+  // and updating metadata. If |callback| is non-null, it will be posted to the
+  // current task runner with the return code.
+  void ReadFromBufferAndPostReply(net::GrowableIOBuffer* in_buf,
+                                  int offset,
+                                  int buf_len,
+                                  net::IOBuffer* out_buf,
+                                  const CompletionCallback& callback);
 
   // Copies data from |buf| to the internal in-memory buffer for stream 0. If
   // |truncate| is set to true, the target buffer will be truncated at |offset|
@@ -334,6 +342,7 @@
   const base::FilePath path_;
   const uint64_t entry_hash_;
   const bool use_optimistic_operations_;
+  bool is_initial_stream1_read_;  // used for metrics only.
   std::string key_;
 
   // |last_used_|, |last_modified_| and |data_size_| are copied from the
@@ -396,6 +405,11 @@
   // used to write HTTP headers, the memory consumption of keeping it in memory
   // is acceptable.
   scoped_refptr<net::GrowableIOBuffer> stream_0_data_;
+
+  // Sometimes stream 1 data is prefetched when stream 0 is first read.
+  // If a write to the stream occurs on the entry the prefetch buffer is
+  // discarded. It may also be null if it wasn't prefetched in the first place.
+  scoped_refptr<net::GrowableIOBuffer> stream_1_prefetch_data_;
 };
 
 }  // namespace disk_cache
diff --git a/net/disk_cache/simple/simple_synchronous_entry.cc b/net/disk_cache/simple/simple_synchronous_entry.cc
index 156e499..0eafe89 100644
--- a/net/disk_cache/simple/simple_synchronous_entry.cc
+++ b/net/disk_cache/simple/simple_synchronous_entry.cc
@@ -13,15 +13,19 @@
 #include "base/files/file_util.h"
 #include "base/hash.h"
 #include "base/location.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/sha1.h"
+#include "base/strings/string_piece.h"
 #include "base/timer/elapsed_timer.h"
 #include "crypto/secure_hash.h"
 #include "net/base/hash_value.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
 #include "net/disk_cache/simple/simple_backend_version.h"
+#include "net/disk_cache/simple/simple_experiment.h"
 #include "net/disk_cache/simple/simple_histogram_enums.h"
 #include "net/disk_cache/simple/simple_histogram_macros.h"
 #include "net/disk_cache/simple/simple_util.h"
@@ -74,6 +78,10 @@
                    static_cast<int>(KeySHA256Result::MAX));
 }
 
+void RecordWhetherOpenDidPrefetch(net::CacheType cache_type, bool result) {
+  SIMPLE_CACHE_UMA(BOOLEAN, "SyncOpenDidPrefetch", cache_type, result);
+}
+
 bool CanOmitEmptyFile(int file_index) {
   DCHECK_GE(file_index, 0);
   DCHECK_LT(file_index, kSimpleEntryFileCount);
@@ -110,6 +118,15 @@
 using simple_util::GetFileSizeFromDataSize;
 using simple_util::GetFileIndexFromStreamIndex;
 
+const base::Feature kSimpleCachePrefetchExperiment = {
+    "SimpleCachePrefetchExperiment", base::FEATURE_DISABLED_BY_DEFAULT};
+const char kSimplePrefetchBytesParam[] = "Bytes";
+
+int GetSimpleCachePrefetchSize() {
+  return base::GetFieldTrialParamByFeatureAsInt(kSimpleCachePrefetchExperiment,
+                                                kSimplePrefetchBytesParam, 0);
+}
+
 SimpleEntryStat::SimpleEntryStat(base::Time last_used,
                                  base::Time last_modified,
                                  const int32_t data_size[],
@@ -162,13 +179,14 @@
   return GetFileSizeFromDataSize(key_length, total_data_size);
 }
 
+SimpleStreamPrefetchData::SimpleStreamPrefetchData()
+    : stream_crc32(crc32(0, Z_NULL, 0)) {}
+
+SimpleStreamPrefetchData::~SimpleStreamPrefetchData() {}
+
 SimpleEntryCreationResults::SimpleEntryCreationResults(
     SimpleEntryStat entry_stat)
-    : sync_entry(NULL),
-      entry_stat(entry_stat),
-      stream_0_crc32(crc32(0, Z_NULL, 0)),
-      result(net::OK) {
-}
+    : sync_entry(NULL), entry_stat(entry_stat), result(net::OK) {}
 
 SimpleEntryCreationResults::~SimpleEntryCreationResults() {
 }
@@ -222,13 +240,13 @@
   SimpleSynchronousEntry* sync_entry =
       new SimpleSynchronousEntry(cache_type, path, key, entry_hash, had_index);
   out_results->result = sync_entry->InitializeForOpen(
-      &out_results->entry_stat, &out_results->stream_0_data,
-      &out_results->stream_0_crc32);
+      &out_results->entry_stat, out_results->stream_prefetch_data);
   if (out_results->result != net::OK) {
     sync_entry->Doom();
     delete sync_entry;
     out_results->sync_entry = NULL;
-    out_results->stream_0_data = NULL;
+    out_results->stream_prefetch_data[0].data = nullptr;
+    out_results->stream_prefetch_data[1].data = nullptr;
     return;
   }
   SIMPLE_CACHE_UMA(TIMES, "DiskOpenLatency", cache_type,
@@ -644,21 +662,22 @@
   *out_result = static_cast<int>(std::min(avail_so_far, len_from_start));
 }
 
-int SimpleSynchronousEntry::CheckEOFRecord(int index,
+int SimpleSynchronousEntry::CheckEOFRecord(int stream_index,
                                            const SimpleEntryStat& entry_stat,
-                                           uint32_t expected_crc32) const {
+                                           uint32_t expected_crc32) {
   DCHECK(initialized_);
-  uint32_t crc32;
-  bool has_crc32;
-  bool has_key_sha256;
-  int32_t stream_size;
-  int rv = GetEOFRecordData(index, entry_stat, &has_crc32, &has_key_sha256,
-                            &crc32, &stream_size);
+  SimpleFileEOF eof_record;
+  int file_offset = entry_stat.GetEOFOffsetInFile(key_.size(), stream_index);
+  int file_index = GetFileIndexFromStreamIndex(stream_index);
+  int rv = GetEOFRecordData(base::StringPiece(), file_index, file_offset,
+                            &eof_record);
+
   if (rv != net::OK) {
     Doom();
     return rv;
   }
-  if (has_crc32 && crc32 != expected_crc32) {
+  if ((eof_record.flags & SimpleFileEOF::FLAG_HAS_CRC32) &&
+      eof_record.data_crc32 != expected_crc32) {
     DVLOG(1) << "EOF record had bad crc.";
     RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_CRC_MISMATCH);
     Doom();
@@ -668,6 +687,37 @@
   return net::OK;
 }
 
+int SimpleSynchronousEntry::PreReadStreamPayload(
+    base::StringPiece file_0_prefetch,
+    int stream_index,
+    int extra_size,
+    const SimpleEntryStat& entry_stat,
+    const SimpleFileEOF& eof_record,
+    SimpleStreamPrefetchData* out) {
+  DCHECK(stream_index == 0 || stream_index == 1);
+
+  int stream_size = entry_stat.data_size(stream_index);
+  int read_size = stream_size + extra_size;
+  out->data = new net::GrowableIOBuffer();
+  out->data->SetCapacity(read_size);
+  int file_offset = entry_stat.GetOffsetInFile(key_.size(), 0, stream_index);
+  if (!ReadFromFileOrPrefetched(file_0_prefetch, 0, file_offset, read_size,
+                                out->data->data()))
+    return net::ERR_FAILED;
+
+  // Check the CRC32.
+  uint32_t expected_crc32 = simple_util::Crc32(out->data->data(), stream_size);
+  if ((eof_record.flags & SimpleFileEOF::FLAG_HAS_CRC32) &&
+      eof_record.data_crc32 != expected_crc32) {
+    DVLOG(1) << "EOF record had bad crc.";
+    RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_CRC_MISMATCH);
+    return net::ERR_CACHE_CHECKSUM_MISMATCH;
+  }
+  out->stream_crc32 = expected_crc32;
+  RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_SUCCESS);
+  return net::OK;
+}
+
 void SimpleSynchronousEntry::Close(
     const SimpleEntryStat& entry_stat,
     std::unique_ptr<std::vector<CRCRecord>> crc32s_to_write,
@@ -905,7 +955,7 @@
     // data_size(2). In the case of file 0, it is the combined size of stream
     // 0, stream 1 and one EOF record. The exact distribution of sizes between
     // stream 1 and stream 0 is only determined after reading the EOF record
-    // for stream 0 in ReadAndValidateStream0.
+    // for stream 0 in ReadAndValidateStream0AndMaybe1.
     if (!base::IsValueInRangeForNumericType<int>(file_info.size)) {
       RecordSyncOpenResult(cache_type_, OPEN_ENTRY_INVALID_FILE_LENGTH,
                            had_index_);
@@ -1049,8 +1099,7 @@
 
 int SimpleSynchronousEntry::InitializeForOpen(
     SimpleEntryStat* out_entry_stat,
-    scoped_refptr<net::GrowableIOBuffer>* stream_0_data,
-    uint32_t* out_stream_0_crc32) {
+    SimpleStreamPrefetchData stream_prefetch_data[2]) {
   DCHECK(!initialized_);
   if (!OpenFiles(out_entry_stat)) {
     DLOG(WARNING) << "Could not open platform files for entry.";
@@ -1078,9 +1127,8 @@
 
     if (i == 0) {
       // File size for stream 0 has been stored temporarily in data_size[1].
-      int ret_value_stream_0 =
-          ReadAndValidateStream0(out_entry_stat->data_size(1), out_entry_stat,
-                                 stream_0_data, out_stream_0_crc32);
+      int ret_value_stream_0 = ReadAndValidateStream0AndMaybe1(
+          out_entry_stat->data_size(1), out_entry_stat, stream_prefetch_data);
       if (ret_value_stream_0 != net::OK)
         return ret_value_stream_0;
     } else {
@@ -1171,65 +1219,89 @@
   return net::OK;
 }
 
-int SimpleSynchronousEntry::ReadAndValidateStream0(
+int SimpleSynchronousEntry::ReadAndValidateStream0AndMaybe1(
     int file_size,
     SimpleEntryStat* out_entry_stat,
-    scoped_refptr<net::GrowableIOBuffer>* stream_0_data,
-    uint32_t* out_stream_0_crc32) {
-  // Pretend this file has a null stream zero, and contains the optional key
-  // SHA256. This is good enough to read the EOF record on the file, which gives
-  // the actual size of stream 0.
-  int temp_data_size = GetDataSizeFromFileSize(key_.size(), file_size);
-  out_entry_stat->set_data_size(0, 0);
-  out_entry_stat->set_data_size(
-      1, temp_data_size - sizeof(net::SHA256HashValue) - sizeof(SimpleFileEOF));
+    SimpleStreamPrefetchData stream_prefetch_data[2]) {
+  // If the file is sufficiently small, we will prefetch everything --
+  // in which case |prefetch_buf| will be non-null, and we should look at it
+  // rather than call ::Read for the bits.
+  std::unique_ptr<char[]> prefetch_buf;
+  base::StringPiece file_0_prefetch;
 
-  bool has_crc32;
-  bool has_key_sha256;
-  uint32_t read_crc32;
-  int32_t stream_0_size;
-  int ret_value_crc32 =
-      GetEOFRecordData(0, *out_entry_stat, &has_crc32, &has_key_sha256,
-                       &read_crc32, &stream_0_size);
-  if (ret_value_crc32 != net::OK)
-    return ret_value_crc32;
+  if (file_size > GetSimpleCachePrefetchSize()) {
+    RecordWhetherOpenDidPrefetch(cache_type_, false);
+  } else {
+    RecordWhetherOpenDidPrefetch(cache_type_, true);
+    prefetch_buf = base::MakeUnique<char[]>(file_size);
+    if (files_[0].Read(0, prefetch_buf.get(), file_size) != file_size)
+      return net::ERR_FAILED;
+    file_0_prefetch.set(prefetch_buf.get(), file_size);
+  }
 
-  // Calculate and set the real values for the two streams.
-  int32_t total_size = out_entry_stat->data_size(1);
-  if (!has_key_sha256)
-    total_size += sizeof(net::SHA256HashValue);
-  if (stream_0_size > total_size)
+  // Read stream 0 footer first --- it has size/feature info required to figure
+  // out file 0's layout.
+  SimpleFileEOF stream_0_eof;
+  int rv = GetEOFRecordData(
+      file_0_prefetch, /* file_index = */ 0,
+      /* file_offset = */ file_size - sizeof(SimpleFileEOF), &stream_0_eof);
+  if (rv != net::OK)
+    return rv;
+
+  int32_t stream_0_size = stream_0_eof.stream_size;
+  if (stream_0_size < 0 || stream_0_size > file_size)
     return net::ERR_FAILED;
   out_entry_stat->set_data_size(0, stream_0_size);
-  out_entry_stat->set_data_size(1, total_size - stream_0_size);
 
-  // Put stream 0 data in memory.
-  *stream_0_data = new net::GrowableIOBuffer();
-  (*stream_0_data)->SetCapacity(stream_0_size + sizeof(net::SHA256HashValue));
-  int file_offset = out_entry_stat->GetOffsetInFile(key_.size(), 0, 0);
-  int read_size = stream_0_size;
+  // Calculate size for stream 1, now we know stream 0's.
+  // See comments in simple_entry_format.h for background.
+  bool has_key_sha256 =
+      (stream_0_eof.flags & SimpleFileEOF::FLAG_HAS_KEY_SHA256) ==
+      SimpleFileEOF::FLAG_HAS_KEY_SHA256;
+  int extra_post_stream_0_read = 0;
   if (has_key_sha256)
-    read_size += sizeof(net::SHA256HashValue);
-  if (files_[0].Read(file_offset, (*stream_0_data)->data(), read_size) !=
-      read_size)
+    extra_post_stream_0_read += sizeof(net::SHA256HashValue);
+
+  int32_t stream1_size = file_size - 2 * sizeof(SimpleFileEOF) - stream_0_size -
+                         sizeof(SimpleFileHeader) - key_.size() -
+                         extra_post_stream_0_read;
+  if (stream1_size < 0 || stream1_size > file_size)
     return net::ERR_FAILED;
 
-  // Check the CRC32.
-  uint32_t expected_crc32 =
-      simple_util::Crc32((*stream_0_data)->data(), stream_0_size);
-  if (has_crc32 && read_crc32 != expected_crc32) {
-    DVLOG(1) << "EOF record had bad crc.";
-    RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_CRC_MISMATCH);
-    return net::ERR_FAILED;
+  out_entry_stat->set_data_size(1, stream1_size);
+
+  // Put stream 0 data in memory --- plus maybe the sha256(key) footer.
+  rv = PreReadStreamPayload(file_0_prefetch, /* stream_index = */ 0,
+                            extra_post_stream_0_read, *out_entry_stat,
+                            stream_0_eof, &stream_prefetch_data[0]);
+  if (rv != net::OK)
+    return rv;
+
+  // If prefetch buffer is available, and we have sha256(key) (so we don't need
+  // to look at the header), extract out stream 1 info as well.
+  if (prefetch_buf && has_key_sha256) {
+    SimpleFileEOF stream_1_eof;
+    rv = GetEOFRecordData(
+        file_0_prefetch, /* file_index = */ 0,
+        out_entry_stat->GetEOFOffsetInFile(key_.size(), /* stream_index = */ 1),
+        &stream_1_eof);
+    if (rv != net::OK)
+      return rv;
+
+    rv = PreReadStreamPayload(file_0_prefetch, /* stream_index = */ 1,
+                              /* extra_size = */ 0, *out_entry_stat,
+                              stream_1_eof, &stream_prefetch_data[1]);
+    if (rv != net::OK)
+      return rv;
   }
-  *out_stream_0_crc32 = expected_crc32;
 
   // If present, check the key SHA256.
   if (has_key_sha256) {
     net::SHA256HashValue hash_value;
     CalculateSHA256OfKey(key_, &hash_value);
     bool matched =
-        std::memcmp(&hash_value, (*stream_0_data)->data() + stream_0_size,
+        std::memcmp(&hash_value,
+                    stream_prefetch_data[0].data->data() + stream_0_size,
                     sizeof(hash_value)) == 0;
     if (!matched) {
       RecordKeySHA256Result(cache_type_, KeySHA256Result::NO_MATCH);
@@ -1246,44 +1318,62 @@
   if (!has_key_sha256 && header_and_key_check_needed_[0])
     CheckHeaderAndKey(0);
 
-  RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_SUCCESS);
   return net::OK;
 }
 
-int SimpleSynchronousEntry::GetEOFRecordData(int index,
-                                             const SimpleEntryStat& entry_stat,
-                                             bool* out_has_crc32,
-                                             bool* out_has_key_sha256,
-                                             uint32_t* out_crc32,
-                                             int32_t* out_data_size) const {
-  SimpleFileEOF eof_record;
-  int file_offset = entry_stat.GetEOFOffsetInFile(key_.size(), index);
-  int file_index = GetFileIndexFromStreamIndex(index);
-  File* file = const_cast<File*>(&files_[file_index]);
-  if (file->Read(file_offset, reinterpret_cast<char*>(&eof_record),
-                 sizeof(eof_record)) !=
-      sizeof(eof_record)) {
+bool SimpleSynchronousEntry::ReadFromFileOrPrefetched(
+    base::StringPiece file_0_prefetch,
+    int file_index,
+    int offset,
+    int size,
+    char* dest) {
+  if (file_0_prefetch.empty() || file_index != 0) {
+    return files_[file_index].Read(offset, dest, size) == size;
+  } else {
+    if (offset < 0 || size < 0)
+      return false;
+    if (size == 0)
+      return true;
+
+    base::CheckedNumeric<size_t> start(offset);
+    size_t start_numeric;
+    if (!start.AssignIfValid(&start_numeric) ||
+        start_numeric >= file_0_prefetch.size())
+      return false;
+
+    base::CheckedNumeric<size_t> end = start + size - 1;
+    size_t end_numeric;
+    if (!end.AssignIfValid(&end_numeric) ||
+        end_numeric >= file_0_prefetch.size())
+      return false;
+
+    memcpy(dest, file_0_prefetch.data() + offset, size);
+    return true;
+  }
+}
+
+int SimpleSynchronousEntry::GetEOFRecordData(base::StringPiece file_0_prefetch,
+                                             int file_index,
+                                             int file_offset,
+                                             SimpleFileEOF* eof_record) {
+  if (!ReadFromFileOrPrefetched(file_0_prefetch, file_index, file_offset,
+                                sizeof(SimpleFileEOF),
+                                reinterpret_cast<char*>(eof_record))) {
     RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_READ_FAILURE);
     return net::ERR_CACHE_CHECKSUM_READ_FAILURE;
   }
 
-  if (eof_record.final_magic_number != kSimpleFinalMagicNumber) {
+  if (eof_record->final_magic_number != kSimpleFinalMagicNumber) {
     RecordCheckEOFResult(cache_type_, CHECK_EOF_RESULT_MAGIC_NUMBER_MISMATCH);
     DVLOG(1) << "EOF record had bad magic number.";
     return net::ERR_CACHE_CHECKSUM_READ_FAILURE;
   }
 
-  if (!base::IsValueInRangeForNumericType<int32_t>(eof_record.stream_size))
+  if (!base::IsValueInRangeForNumericType<int32_t>(eof_record->stream_size))
     return net::ERR_FAILED;
-
-  *out_has_crc32 = (eof_record.flags & SimpleFileEOF::FLAG_HAS_CRC32) ==
-                   SimpleFileEOF::FLAG_HAS_CRC32;
-  *out_has_key_sha256 =
-      (eof_record.flags & SimpleFileEOF::FLAG_HAS_KEY_SHA256) ==
-      SimpleFileEOF::FLAG_HAS_KEY_SHA256;
-  *out_crc32 = eof_record.data_crc32;
-  *out_data_size = eof_record.stream_size;
-  SIMPLE_CACHE_UMA(BOOLEAN, "SyncCheckEOFHasCrc", cache_type_, *out_has_crc32);
+  SIMPLE_CACHE_UMA(BOOLEAN, "SyncCheckEOFHasCrc", cache_type_,
+                   (eof_record->flags & SimpleFileEOF::FLAG_HAS_CRC32) ==
+                       SimpleFileEOF::FLAG_HAS_CRC32);
   return net::OK;
 }
 
diff --git a/net/disk_cache/simple/simple_synchronous_entry.h b/net/disk_cache/simple/simple_synchronous_entry.h
index a7e6e66b..14b5b0d0 100644
--- a/net/disk_cache/simple/simple_synchronous_entry.h
+++ b/net/disk_cache/simple/simple_synchronous_entry.h
@@ -14,10 +14,12 @@
 #include <utility>
 #include <vector>
 
+#include "base/feature_list.h"
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/ref_counted.h"
+#include "base/strings/string_piece_forward.h"
 #include "base/time/time.h"
 #include "net/base/cache_type.h"
 #include "net/base/net_export.h"
@@ -32,6 +34,13 @@
 
 namespace disk_cache {
 
+NET_EXPORT_PRIVATE extern const base::Feature kSimpleCachePrefetchExperiment;
+NET_EXPORT_PRIVATE extern const char kSimplePrefetchBytesParam[];
+
+// Returns how large a file would get prefetched on reading the entry.
+// If the experiment is disabled, returns 0.
+NET_EXPORT_PRIVATE int GetSimpleCachePrefetchSize();
+
 class SimpleSynchronousEntry;
 
 // This class handles the passing of data about the entry between
@@ -73,14 +82,24 @@
   int32_t sparse_data_size_;
 };
 
+struct SimpleStreamPrefetchData {
+  SimpleStreamPrefetchData();
+  ~SimpleStreamPrefetchData();
+
+  scoped_refptr<net::GrowableIOBuffer> data;
+  uint32_t stream_crc32;
+};
+
 struct SimpleEntryCreationResults {
   explicit SimpleEntryCreationResults(SimpleEntryStat entry_stat);
   ~SimpleEntryCreationResults();
 
   SimpleSynchronousEntry* sync_entry;
-  scoped_refptr<net::GrowableIOBuffer> stream_0_data;
+
+  // Expectation is that [0] will always be filled in, but [1] might not be.
+  SimpleStreamPrefetchData stream_prefetch_data[2];
+
   SimpleEntryStat entry_stat;
-  uint32_t stream_0_crc32;
   int result;
 };
 
@@ -188,9 +207,9 @@
                  net::IOBuffer* in_buf,
                  SimpleEntryStat* out_entry_stat,
                  int* out_result);
-  int CheckEOFRecord(int index,
+  int CheckEOFRecord(int stream_index,
                      const SimpleEntryStat& entry_stat,
-                     uint32_t expected_crc32) const;
+                     uint32_t expected_crc32);
 
   void ReadSparseData(const EntryOperationData& in_entry_op,
                       net::IOBuffer* out_buf,
@@ -281,8 +300,7 @@
 
   // Returns a net error, i.e. net::OK on success.
   int InitializeForOpen(SimpleEntryStat* out_entry_stat,
-                        scoped_refptr<net::GrowableIOBuffer>* stream_0_data,
-                        uint32_t* out_stream_0_crc32);
+                        SimpleStreamPrefetchData stream_prefetch_data[2]);
 
   // Writes the header and key to a newly-created stream file. |index| is the
   // index of the stream. Returns true on success; returns false and sets
@@ -294,19 +312,45 @@
   int InitializeForCreate(SimpleEntryStat* out_entry_stat);
 
   // Allocates and fills a buffer with stream 0 data in |stream_0_data|, then
-  // checks its crc32.
-  int ReadAndValidateStream0(
+  // checks its crc32. May also optionally read in |stream_1_data| and its
+  // crc, but might decide not to.
+  int ReadAndValidateStream0AndMaybe1(
       int file_size,
       SimpleEntryStat* out_entry_stat,
-      scoped_refptr<net::GrowableIOBuffer>* stream_0_data,
-      uint32_t* out_stream_0_crc32);
+      SimpleStreamPrefetchData stream_prefetch_data[2]);
 
-  int GetEOFRecordData(int index,
-                       const SimpleEntryStat& entry_stat,
-                       bool* out_has_crc32,
-                       bool* out_has_key_sha256,
-                       uint32_t* out_crc32,
-                       int32_t* out_data_size) const;
+  // Reads the EOF record located at |file_offset| in file |file_index|,
+  // with |file_0_prefetch| ptentially having prefetched file 0 content.
+  // Puts the result into |*eof_record| and sanity-checks it.
+  // Returns net status, and records any failures to UMA.
+  int GetEOFRecordData(base::StringPiece file_0_prefetch,
+                       int file_index,
+                       int file_offset,
+                       SimpleFileEOF* eof_record);
+
+  // Reads either from |file_0_prefetch| or files_[file_index].
+  // Range-checks all the in-memory reads.
+  bool ReadFromFileOrPrefetched(base::StringPiece file_0_prefetch,
+                                int file_index,
+                                int offset,
+                                int size,
+                                char* dest);
+
+  // Extracts out the payload of stream |stream_index|, reading either from
+  // |file_0_prefetch|, if available, or the file. |entry_stat| will be used to
+  // determine file layout, though |extra_size| additional bytes will be read
+  // past the stream payload end.
+  //
+  // |*stream_data| will be pointed to a fresh buffer with the results,
+  // and |*out_crc32| will get the checksum, which will be verified against
+  // |eof_record|.
+  int PreReadStreamPayload(base::StringPiece file_0_prefetch,
+                           int stream_index,
+                           int extra_size,
+                           const SimpleEntryStat& entry_stat,
+                           const SimpleFileEOF& eof_record,
+                           SimpleStreamPrefetchData* out);
+
   void Doom() const;
 
   // Opens the sparse data file and scans it if it exists.
diff --git a/net/dns/host_cache.cc b/net/dns/host_cache.cc
index 50759e1..3d55d64f 100644
--- a/net/dns/host_cache.cc
+++ b/net/dns/host_cache.cc
@@ -145,7 +145,10 @@
 }
 
 HostCache::HostCache(size_t max_entries)
-    : max_entries_(max_entries), network_changes_(0), delegate_(nullptr) {}
+    : max_entries_(max_entries),
+      network_changes_(0),
+      restore_size_(0),
+      delegate_(nullptr) {}
 
 HostCache::~HostCache() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
@@ -393,6 +396,7 @@
                           network_changes_ - 1));
     }
   }
+  restore_size_ = old_cache.GetSize();
   return true;
 }
 
diff --git a/net/dns/host_cache.h b/net/dns/host_cache.h
index e4cdf05..d756815 100644
--- a/net/dns/host_cache.h
+++ b/net/dns/host_cache.h
@@ -119,7 +119,7 @@
     base::TimeDelta ttl_;
 
     base::TimeTicks expires_;
-    // Copied from the cache's network_changes_ when the entry is set; can0
+    // Copied from the cache's network_changes_ when the entry is set; can
     // later be compared to it to see if the entry was received on the current
     // network.
     int network_changes_;
@@ -188,6 +188,9 @@
   // cache, skipping any that already have entries. Returns true on success,
   // false on failure.
   bool RestoreFromListValue(const base::ListValue& old_cache);
+  // Returns the number of entries that were restored in the last call to
+  // RestoreFromListValue().
+  size_t last_restore_size() const { return restore_size_; }
 
   // Returns the number of entries in the cache.
   size_t size() const;
@@ -235,6 +238,9 @@
   size_t max_entries_;
   int network_changes_;
   EvictionCallback eviction_callback_;
+  // Number of cache entries that were restored in the last call to
+  // RestoreFromListValue(). Used in histograms.
+  size_t restore_size_;
 
   PersistenceDelegate* delegate_;
 
diff --git a/net/dns/host_cache_unittest.cc b/net/dns/host_cache_unittest.cc
index f1ac984..c9fc7dd 100644
--- a/net/dns/host_cache_unittest.cc
+++ b/net/dns/host_cache_unittest.cc
@@ -701,6 +701,8 @@
   EXPECT_TRUE(cache.Lookup(key3, now));
   EXPECT_EQ(3u, cache.size());
 
+  EXPECT_EQ(0u, cache.last_restore_size());
+
   // Advance to t=12, ansd serialize the cache.
   now += base::TimeDelta::FromSeconds(7);
 
@@ -720,6 +722,8 @@
   EXPECT_TRUE(restored_cache.Lookup(key4, now));
   EXPECT_EQ(2u, restored_cache.size());
 
+  EXPECT_EQ(0u, restored_cache.last_restore_size());
+
   restored_cache.RestoreFromListValue(serialized_cache);
 
   HostCache::EntryStaleness stale;
@@ -761,6 +765,8 @@
   EXPECT_TRUE(result4);
   EXPECT_EQ(1u, result4->addresses().size());
   EXPECT_EQ(address_ipv4, result4->addresses().front().address());
+
+  EXPECT_EQ(3u, restored_cache.last_restore_size());
 }
 
 TEST(HostCacheTest, PersistenceDelegate) {
diff --git a/net/dns/host_resolver_impl.cc b/net/dns/host_resolver_impl.cc
index 161f740..2584d8f1 100644
--- a/net/dns/host_resolver_impl.cc
+++ b/net/dns/host_resolver_impl.cc
@@ -2183,6 +2183,18 @@
   return rv;
 }
 
+size_t HostResolverImpl::LastRestoredCacheSize() const {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+  return cache_ ? cache_->last_restore_size() : 0;
+}
+
+size_t HostResolverImpl::CacheSize() const {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+  return cache_ ? cache_->size() : 0;
+}
+
 void HostResolverImpl::SetNoIPv6OnWifi(bool no_ipv6_on_wifi) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   assume_ipv6_failure_on_wifi_ = no_ipv6_on_wifi;
diff --git a/net/dns/host_resolver_impl.h b/net/dns/host_resolver_impl.h
index f833e36..a7de17ea 100644
--- a/net/dns/host_resolver_impl.h
+++ b/net/dns/host_resolver_impl.h
@@ -152,6 +152,11 @@
                             AddressList* addresses,
                             HostCache::EntryStaleness* stale_info,
                             const NetLogWithSource& source_net_log);
+  // Returns the number of host cache entries that were restored, or 0 if there
+  // is no cache.
+  size_t LastRestoredCacheSize() const;
+  // Returns the number of entries in the host cache, or 0 if there is no cache.
+  size_t CacheSize() const;
 
   void InitializePersistence(
       const PersistCallback& persist_callback,
diff --git a/net/http/http_response_info.cc b/net/http/http_response_info.cc
index 47b0ded..5611777 100644
--- a/net/http/http_response_info.cc
+++ b/net/http/http_response_info.cc
@@ -46,7 +46,7 @@
   // Prior to TLS 1.3, only ECDHE ciphers have groups.
   const SSL_CIPHER* cipher = SSL_get_cipher_by_value(
       SSLConnectionStatusToCipherSuite(ssl_connection_status));
-  return cipher && SSL_CIPHER_is_ECDHE(cipher);
+  return cipher && SSL_CIPHER_get_kx_nid(cipher) == NID_kx_ecdhe;
 }
 
 }  // namespace
diff --git a/net/test/spawned_test_server/remote_test_server.cc b/net/test/spawned_test_server/remote_test_server.cc
index f000ff8..9b4a288 100644
--- a/net/test/spawned_test_server/remote_test_server.cc
+++ b/net/test/spawned_test_server/remote_test_server.cc
@@ -13,6 +13,7 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/json/json_writer.h"
+#include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/path_service.h"
@@ -29,6 +30,31 @@
 
 namespace {
 
+// Based on how the Android runner sets things up, it is only valid for one
+// RemoteTestServer to be active on the device at a time.
+class RemoteTestServerTracker {
+ public:
+  void StartingServer() {
+    base::AutoLock lock(lock_);
+    CHECK_EQ(count_, 0);
+    count_++;
+  }
+
+  void StoppingServer() {
+    base::AutoLock lock(lock_);
+    CHECK_EQ(count_, 1);
+    count_--;
+  }
+
+ private:
+  // |lock_| protects access to |count_|.
+  base::Lock lock_;
+  int count_ = 0;
+};
+
+base::LazyInstance<RemoteTestServerTracker>::Leaky tracker =
+    LAZY_INSTANCE_INITIALIZER;
+
 // Please keep it sync with dictionary SERVER_TYPES in testserver.py
 std::string GetServerTypeString(BaseTestServer::Type type) {
   switch (type) {
@@ -75,6 +101,8 @@
   if (spawner_communicator_.get())
     return true;
 
+  tracker.Get().StartingServer();
+
   spawner_communicator_ =
       std::make_unique<SpawnerCommunicator>(RemoteTestServerConfig::Load());
 
@@ -119,18 +147,19 @@
 }
 
 bool RemoteTestServer::Stop() {
-  if (!spawner_communicator_)
+  if (!spawner_communicator_.get())
     return true;
 
-  uint16_t port = GetPort();
+  tracker.Get().StoppingServer();
+
   CleanUpWhenStoppingServer();
-  bool stopped = spawner_communicator_->StopServer(port);
+  bool stopped = spawner_communicator_->StopServer();
 
   if (!stopped)
     LOG(ERROR) << "Failed stopping RemoteTestServer";
 
   // Explicitly reset |spawner_communicator_| to avoid reusing the stopped one.
-  spawner_communicator_.reset();
+  spawner_communicator_.reset(NULL);
   return stopped;
 }
 
diff --git a/net/test/spawned_test_server/spawner_communicator.cc b/net/test/spawned_test_server/spawner_communicator.cc
index 8968045..9727c24 100644
--- a/net/test/spawned_test_server/spawner_communicator.cc
+++ b/net/test/spawned_test_server/spawner_communicator.cc
@@ -4,8 +4,6 @@
 
 #include "net/test/spawned_test_server/spawner_communicator.h"
 
-#include <inttypes.h>
-
 #include <limits>
 #include <utility>
 
@@ -324,7 +322,7 @@
   return result == OK;
 }
 
-bool SpawnerCommunicator::StopServer(uint16_t port) {
+bool SpawnerCommunicator::StopServer() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   // It's OK to stop the SpawnerCommunicator without starting it. Some tests
   // have test server on their test fixture but do not actually use it.
@@ -334,9 +332,7 @@
   // When the test is done, ask the test server spawner to kill the test server
   // on the remote machine.
   std::string server_return_data;
-  std::string command = base::StringPrintf("kill?port=%" PRIu16, port);
-  int result =
-      SendCommandAndWaitForResult(command, std::string(), &server_return_data);
+  int result = SendCommandAndWaitForResult("kill", "", &server_return_data);
   Shutdown();
   if (result != OK || server_return_data != "killed")
     return false;
diff --git a/net/test/spawned_test_server/spawner_communicator.h b/net/test/spawned_test_server/spawner_communicator.h
index 958cc79..ad3bba5 100644
--- a/net/test/spawned_test_server/spawner_communicator.h
+++ b/net/test/spawned_test_server/spawner_communicator.h
@@ -53,7 +53,7 @@
 // (2) Kill Python test server, format is:
 // Path: "/kill".
 // Method: "GET".
-// Data to server: port=<server_port>.
+// Data to server: None.
 // Data from server: String "killed" returned if success.
 //
 // (3) Ping Python test server to see whether it is alive, format is:
@@ -75,7 +75,7 @@
   // data returned by the spawner.
   bool StartServer(const std::string& arguments,
                    std::string* server_data) WARN_UNUSED_RESULT;
-  bool StopServer(uint16_t port) WARN_UNUSED_RESULT;
+  bool StopServer() WARN_UNUSED_RESULT;
 
  private:
   // Starts the IO thread. Called on the user thread.
diff --git a/remoting/host/native_messaging/pipe_messaging_channel.cc b/remoting/host/native_messaging/pipe_messaging_channel.cc
index 0b288a1..93cd273 100644
--- a/remoting/host/native_messaging/pipe_messaging_channel.cc
+++ b/remoting/host/native_messaging/pipe_messaging_channel.cc
@@ -15,6 +15,8 @@
 
 #if defined(OS_POSIX)
 #include <unistd.h>
+
+#include "base/posix/eintr_wrapper.h"
 #endif
 
 namespace {
@@ -34,7 +36,7 @@
   }
   return base::File(result);
 #elif defined(OS_POSIX)
-  result = dup(file.GetPlatformFile());
+  result = HANDLE_EINTR(dup(file.GetPlatformFile()));
   return base::File(result);
 #else
 #error Not implemented.
diff --git a/remoting/webapp/base/js/chromoting_event.js b/remoting/webapp/base/js/chromoting_event.js
index d1e4c807..2d8d3d03 100644
--- a/remoting/webapp/base/js/chromoting_event.js
+++ b/remoting/webapp/base/js/chromoting_event.js
@@ -269,7 +269,7 @@
  */
 remoting.ChromotingEvent.ChromotingDotComMigration = function(event, phase) {
   /** @type {!remoting.ChromotingEvent.ChromotingDotComMigration.Event} */
-  this.event = event;
+  this.event_type = event;
   /** @type {!remoting.ChromotingEvent.ChromotingDotComMigration.Phase} */
   this.phase = phase;
 };
diff --git a/remoting/webapp/crd/js/butter_bar_unittest.js b/remoting/webapp/crd/js/butter_bar_unittest.js
index 880de4f..bb9fb7ac0 100644
--- a/remoting/webapp/crd/js/butter_bar_unittest.js
+++ b/remoting/webapp/crd/js/butter_bar_unittest.js
@@ -14,7 +14,7 @@
       actual.type, remoting.ChromotingEvent.Type.CHROMOTING_DOT_COM_MIGRATION,
       'ChromotingEvent.type == CHROMOTING_DOT_COM_MIGRATION');
   assert.equal(
-      actual.chromoting_dot_com_migration.event, expectedEvent,
+      actual.chromoting_dot_com_migration.event_type, expectedEvent,
       'ChromotingEvent.chromoting_dot_com_migration.event matched.');
   assert.equal(
       actual.chromoting_dot_com_migration.phase, expectedPhase,
diff --git a/remoting/webapp/crd/manifest.json.jinja2 b/remoting/webapp/crd/manifest.json.jinja2
index aa094bc..fe97207 100644
--- a/remoting/webapp/crd/manifest.json.jinja2
+++ b/remoting/webapp/crd/manifest.json.jinja2
@@ -71,6 +71,7 @@
   },
   "externally_connectable": {
     "matches": [
+      "https://remotedesktop.google.com/*"
     ]
   }
 }
diff --git a/sandbox/linux/services/resource_limits.cc b/sandbox/linux/services/resource_limits.cc
index 51f13c3..0980b88d 100644
--- a/sandbox/linux/services/resource_limits.cc
+++ b/sandbox/linux/services/resource_limits.cc
@@ -35,9 +35,11 @@
   struct rlimit old_rlimit;
   if (getrlimit(resource, &old_rlimit))
     return false;
-  base::CheckedNumeric<rlim_t> limit = old_rlimit.rlim_cur;
-  limit += change;
-  const struct rlimit new_rlimit = {limit.ValueOrDie(), old_rlimit.rlim_max};
+  base::CheckedNumeric<rlim_t> checked_limit = old_rlimit.rlim_cur;
+  checked_limit += change;
+  const rlim_t new_limit = checked_limit.ValueOrDefault(old_rlimit.rlim_max);
+  const struct rlimit new_rlimit = {std::min(new_limit, old_rlimit.rlim_max),
+                                    old_rlimit.rlim_max};
   // setrlimit will fail if limit > old_rlimit.rlim_max.
   return setrlimit(resource, &new_rlimit) == 0;
 }
diff --git a/sandbox/linux/services/resource_limits.h b/sandbox/linux/services/resource_limits.h
index ab949dd..00fa9032 100644
--- a/sandbox/linux/services/resource_limits.h
+++ b/sandbox/linux/services/resource_limits.h
@@ -24,9 +24,10 @@
   static bool LowerSoftAndHardLimits(int resource,
                                      rlim_t soft_limit,
                                      rlim_t hard_limit) WARN_UNUSED_RESULT;
-  // Change soft limit of |resource| to the current limit plus |change|.  Fails
-  // and returns false if the new soft limit would be greater than the hard
-  // limit.
+  // Change soft limit of |resource| to the current limit plus |change|. If
+  // |resource + change| is larger than the hard limit, the soft limit is set to
+  // be the same as the hard limit. Fails and returns false if the underlying
+  // call to setrlimit fails.
   static bool AdjustCurrent(int resource,
                             long long int change) WARN_UNUSED_RESULT;
 
diff --git a/services/ui/manifest.json b/services/ui/manifest.json
index 5c58609..0099631 100644
--- a/services/ui/manifest.json
+++ b/services/ui/manifest.json
@@ -20,7 +20,7 @@
         // Interfaces provided by mus-gpu for mus-ws.
         "ozone": [
           "ui::ozone::mojom::DeviceCursor",
-          "ui::ozone::mojom::GpuAdapter"
+          "ui::ozone::mojom::DrmDevice"
         ],
         "test": [
           "ui::mojom::WindowServerTest"
diff --git a/services/ui/public/interfaces/window_manager.mojom b/services/ui/public/interfaces/window_manager.mojom
index 4f4f7f26..4ac72a9 100644
--- a/services/ui/public/interfaces/window_manager.mojom
+++ b/services/ui/public/interfaces/window_manager.mojom
@@ -305,8 +305,7 @@
   SetDisplayRoot(display.mojom.Display display,
                  WmViewportMetrics viewport_metrics,
                  bool is_primary_display,
-                 uint32 window_id) =>
-      (cc.mojom.LocalSurfaceId? local_surface_id);
+                 uint32 window_id) => (bool success);
 
   // Configures the metrics for the displays and notifies observers. This is
   // only applicable when WindowTree was created with a value of false for
diff --git a/services/ui/ws/event_dispatcher.cc b/services/ui/ws/event_dispatcher.cc
index c0f26a6..5e932f23 100644
--- a/services/ui/ws/event_dispatcher.cc
+++ b/services/ui/ws/event_dispatcher.cc
@@ -37,6 +37,15 @@
          button_only_flags == ui::EF_RIGHT_MOUSE_BUTTON;
 }
 
+// This is meant to mirror when implicit capture stops. Specifically non-mouse
+// pointer up, or mouse and no more buttons down.
+bool IsPointerGoingUp(const PointerEvent& event) {
+  return (event.type() == ui::ET_POINTER_UP ||
+          event.type() == ui::ET_POINTER_CANCELLED) &&
+         (!event.IsMousePointerEvent() ||
+          IsOnlyOneMouseButtonDown(event.flags()));
+}
+
 }  // namespace
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -216,8 +225,8 @@
 void EventDispatcher::UpdateNonClientAreaForCurrentWindow() {
   if (mouse_cursor_source_window_) {
     event_targeter_->FindTargetForLocation(
-        EventSource::MOUSE, mouse_pointer_last_location_,
-        mouse_pointer_display_id_,
+        EventSource::MOUSE,
+        {mouse_pointer_last_location_, mouse_pointer_display_id_},
         base::BindOnce(
             &EventDispatcher::UpdateNonClientAreaForCurrentWindowOnFoundWindow,
             base::Unretained(this)));
@@ -227,8 +236,8 @@
 void EventDispatcher::UpdateCursorProviderByLastKnownLocation() {
   if (!mouse_button_down_) {
     event_targeter_->FindTargetForLocation(
-        EventSource::MOUSE, mouse_pointer_last_location_,
-        mouse_pointer_display_id_,
+        EventSource::MOUSE,
+        {mouse_pointer_last_location_, mouse_pointer_display_id_},
         base::BindOnce(&EventDispatcher::
                            UpdateCursorProviderByLastKnownLocationOnFoundWindow,
                        base::Unretained(this)));
@@ -317,7 +326,8 @@
   const EventSource event_source =
       event.IsMousePointerEvent() ? EventSource::MOUSE : EventSource::TOUCH;
   event_targeter_->FindTargetForLocation(
-      event_source, event.AsPointerEvent()->root_location(), event_display_id_,
+      event_source,
+      {event.AsPointerEvent()->root_location(), event_display_id_},
       base::BindOnce(&EventDispatcher::ProcessPointerEventOnFoundTarget,
                      base::Unretained(this), *event.AsPointerEvent()));
 }
@@ -342,23 +352,21 @@
   return delegate_->GetWindowFromFrameSinkId(frame_sink_id);
 }
 
-LocationTarget EventDispatcher::AdjustLocationTargetForModal(
-    const LocationTarget& location_target) const {
+DeepestWindow EventDispatcher::AdjustTargetForModal(
+    const DeepestWindow& target) const {
   const ServerWindow* modal_transient =
-      modal_window_controller_.GetModalTransient(
-          location_target.deepest_window.window);
-  if (!modal_transient && !modal_window_controller_.IsWindowBlocked(
-                              location_target.deepest_window.window)) {
-    return location_target;
+      modal_window_controller_.GetModalTransient(target.window);
+  if (!modal_transient &&
+      !modal_window_controller_.IsWindowBlocked(target.window)) {
+    return target;
   }
 
-  LocationTarget updated_target = location_target;
-  updated_target.deepest_window.in_non_client_area = true;
-  updated_target.deepest_window.window =
-      location_target.deepest_window.window
-          ? delegate_->GetFallbackTargetForEventBlockedByModal(
-                location_target.deepest_window.window->GetRootForDrawn())
-          : nullptr;
+  DeepestWindow updated_target = target;
+  updated_target.in_non_client_area = true;
+  updated_target.window =
+      target.window ? delegate_->GetFallbackTargetForEventBlockedByModal(
+                          target.window->GetRootForDrawn())
+                    : nullptr;
   return updated_target;
 }
 
@@ -432,49 +440,19 @@
 
 void EventDispatcher::ProcessPointerEventOnFoundTarget(
     const ui::PointerEvent& event,
-    const LocationTarget& found_location_target) {
-  const LocationTarget location_target =
-      AdjustLocationTargetForModal(found_location_target);
-  PointerTarget pointer_target;
-  pointer_target.is_mouse_event = event.IsMousePointerEvent();
-  pointer_target.window = location_target.deepest_window.window;
-  pointer_target.in_nonclient_area =
-      location_target.deepest_window.in_non_client_area;
-  pointer_target.is_pointer_down = event.type() == ui::ET_POINTER_DOWN;
-
+    const DisplayLocation& display_location,
+    const DeepestWindow& found_target) {
   std::unique_ptr<ui::Event> cloned_event = ui::Event::Clone(event);
-  if (location_target.display_id != event_display_id_) {
-    event_display_id_ = location_target.display_id;
+  if (display_location.display_id != event_display_id_) {
+    event_display_id_ = display_location.display_id;
     cloned_event->AsLocatedEvent()->set_root_location(
-        location_target.location_in_root);
+        display_location.location);
   }
 
+  UpdateCursorRelatedProperties(event, display_location);
+
   const bool is_mouse_event = event.IsMousePointerEvent();
-
-  if (is_mouse_event) {
-    // This corresponds to the code in CompoundEventFilter which updates
-    // visibility on each mouse event. Here, we're sure that we're a non-exit
-    // mouse event and FROM_TOUCH doesn't exist in mus so we shouldn't need
-    // further filtering.
-    delegate_->OnEventChangesCursorTouchVisibility(event, true);
-    delegate_->OnEventChangesCursorVisibility(event, true);
-
-    SetMousePointerLocation(location_target.location_in_root,
-                            location_target.display_id);
-    delegate_->OnMouseCursorLocationChanged(location_target.location_in_root,
-                                            location_target.display_id);
-  } else {
-    // When we have a non-touch event that wasn't synthesized, hide the mouse
-    // cursor until the next non-synthesized mouse event.
-    delegate_->OnEventChangesCursorTouchVisibility(event, false);
-  }
-
-  // Release capture on pointer up. For mouse we only release if there are
-  // no buttons down.
-  const bool is_pointer_going_up =
-      (event.type() == ui::ET_POINTER_UP ||
-       event.type() == ui::ET_POINTER_CANCELLED) &&
-      (!is_mouse_event || IsOnlyOneMouseButtonDown(event.flags()));
+  const bool is_pointer_going_up = IsPointerGoingUp(event);
 
   // Update mouse down state upon events which change it.
   if (is_mouse_event) {
@@ -490,10 +468,10 @@
     }
   }
 
-  if (drag_controller_) {
-    if (drag_controller_->DispatchPointerEvent(*cloned_event->AsPointerEvent(),
-                                               pointer_target.window))
-      return;
+  if (drag_controller_ && drag_controller_->DispatchPointerEvent(
+                              *cloned_event->AsPointerEvent(),
+                              AdjustTargetForModal(found_target).window)) {
+    return;
   }
 
   if (capture_window_) {
@@ -503,7 +481,15 @@
     return;
   }
 
+  DeepestWindow updated_target = AdjustTargetForModal(found_target);
+  PointerTarget pointer_target;
+  pointer_target.is_mouse_event = is_mouse_event;
+  pointer_target.window = updated_target.window;
+  pointer_target.in_nonclient_area = updated_target.in_non_client_area;
+  pointer_target.is_pointer_down = event.type() == ui::ET_POINTER_DOWN;
+
   const int32_t pointer_id = event.pointer_details().id;
+
   if (!IsTrackingPointer(pointer_id) ||
       !pointer_targets_[pointer_id].is_pointer_down) {
     const bool any_pointers_down = AreAnyPointersDown();
@@ -538,7 +524,7 @@
   // before we perform dispatch because the Delegate is going to read this
   // information from us.
   if (is_pointer_going_up && is_mouse_event)
-    UpdateCursorProvider(location_target);
+    UpdateCursorProvider(updated_target);
 
   DispatchToPointerTarget(pointer_targets_[pointer_id],
                           *cloned_event->AsPointerEvent());
@@ -552,58 +538,61 @@
       delegate_->ReleaseNativeCapture();
   }
 
-  if (event.type() == ET_POINTER_DOWN &&
-      found_location_target.deepest_window.window) {
-    // Use |found_location_target| as |location_target| has already been
-    // adjusted for the modal window.
-    ServerWindow* modal_transient = modal_window_controller_.GetModalTransient(
-        found_location_target.deepest_window.window);
-    if (modal_transient) {
-      ServerWindow* toplevel = modal_window_controller_.GetToplevelWindow(
-          found_location_target.deepest_window.window);
-      DCHECK(toplevel);
-      delegate_->SetFocusedWindowFromEventDispatcher(toplevel);
-      delegate_->OnEventOccurredOutsideOfModalWindow(modal_transient);
-    } else if (found_location_target.deepest_window.window->IsDrawn() &&
-               modal_window_controller_.IsWindowBlocked(
-                   found_location_target.deepest_window.window) &&
-               modal_window_controller_.GetActiveSystemModalWindow()) {
-      delegate_->OnEventOccurredOutsideOfModalWindow(
-          modal_window_controller_.GetActiveSystemModalWindow());
-    }
+  // Use |found_target| as |updated_target| has already been adjusted for the
+  // modal window.
+  if (event.type() == ET_POINTER_DOWN && found_target.window)
+    HandleClickOnBlockedWindow(found_target);
+}
+
+void EventDispatcher::UpdateCursorRelatedProperties(
+    const ui::PointerEvent& event,
+    const DisplayLocation& display_location) {
+  if (event.IsMousePointerEvent()) {
+    // This corresponds to the code in CompoundEventFilter which updates
+    // visibility on each mouse event. Here, we're sure that we're a non-exit
+    // mouse event and FROM_TOUCH doesn't exist in mus so we shouldn't need
+    // further filtering.
+    delegate_->OnEventChangesCursorTouchVisibility(event, true);
+    delegate_->OnEventChangesCursorVisibility(event, true);
+
+    SetMousePointerLocation(display_location.location,
+                            display_location.display_id);
+    delegate_->OnMouseCursorLocationChanged(display_location.location,
+                                            display_location.display_id);
+  } else {
+    // When we have a non-touch event that wasn't synthesized, hide the mouse
+    // cursor until the next non-synthesized mouse event.
+    delegate_->OnEventChangesCursorTouchVisibility(event, false);
   }
 }
 
 void EventDispatcher::UpdateNonClientAreaForCurrentWindowOnFoundWindow(
-    const LocationTarget& found_location_target) {
+    const DisplayLocation& display_location,
+    const DeepestWindow& target) {
   if (!mouse_cursor_source_window_)
     return;
 
-  const LocationTarget location_target =
-      AdjustLocationTargetForModal(found_location_target);
-  if (location_target.deepest_window.window == mouse_cursor_source_window_) {
+  const DeepestWindow updated_target = AdjustTargetForModal(target);
+  if (updated_target.window == mouse_cursor_source_window_) {
     mouse_cursor_in_non_client_area_ =
-        mouse_cursor_source_window_
-            ? location_target.deepest_window.in_non_client_area
-            : false;
+        mouse_cursor_source_window_ ? updated_target.in_non_client_area : false;
   }
   delegate_->UpdateNativeCursorFromDispatcher();
 }
 
 void EventDispatcher::UpdateCursorProviderByLastKnownLocationOnFoundWindow(
-    const LocationTarget& location_target) {
-  UpdateCursorProvider(AdjustLocationTargetForModal(location_target));
+    const DisplayLocation& display_location,
+    const DeepestWindow& target) {
+  UpdateCursorProvider(AdjustTargetForModal(target));
 }
 
-void EventDispatcher::UpdateCursorProvider(
-    const LocationTarget& location_target) {
+void EventDispatcher::UpdateCursorProvider(const DeepestWindow& target) {
   if (mouse_button_down_)
     return;
 
-  SetMouseCursorSourceWindow(location_target.deepest_window.window);
+  SetMouseCursorSourceWindow(target.window);
   if (mouse_cursor_source_window_) {
-    mouse_cursor_in_non_client_area_ =
-        location_target.deepest_window.in_non_client_area;
+    mouse_cursor_in_non_client_area_ = target.in_non_client_area;
   } else {
     SetMouseCursorSourceWindow(delegate_->GetRootWindowContaining(
         &mouse_pointer_last_location_, &mouse_pointer_display_id_));
@@ -612,6 +601,23 @@
   delegate_->UpdateNativeCursorFromDispatcher();
 }
 
+void EventDispatcher::HandleClickOnBlockedWindow(const DeepestWindow& target) {
+  ServerWindow* modal_transient =
+      modal_window_controller_.GetModalTransient(target.window);
+  if (modal_transient) {
+    ServerWindow* toplevel =
+        modal_window_controller_.GetToplevelWindow(target.window);
+    DCHECK(toplevel);
+    delegate_->SetFocusedWindowFromEventDispatcher(toplevel);
+    delegate_->OnEventOccurredOutsideOfModalWindow(modal_transient);
+  } else if (target.window->IsDrawn() &&
+             modal_window_controller_.IsWindowBlocked(target.window) &&
+             modal_window_controller_.GetActiveSystemModalWindow()) {
+    delegate_->OnEventOccurredOutsideOfModalWindow(
+        modal_window_controller_.GetActiveSystemModalWindow());
+  }
+}
+
 void EventDispatcher::StartTrackingPointer(
     int32_t pointer_id,
     const PointerTarget& pointer_target) {
diff --git a/services/ui/ws/event_dispatcher.h b/services/ui/ws/event_dispatcher.h
index 83df1582..50851f7 100644
--- a/services/ui/ws/event_dispatcher.h
+++ b/services/ui/ws/event_dispatcher.h
@@ -42,6 +42,8 @@
 class EventDispatcherDelegate;
 class ServerWindow;
 
+struct DisplayLocation;
+
 namespace test {
 class EventDispatcherTestApi;
 }
@@ -199,8 +201,7 @@
   // EventTargeter returns the deepest window based on hit-test data. If the
   // target is blocked by a modal window this returns a different target,
   // otherwise the supplied target is returned.
-  LocationTarget AdjustLocationTargetForModal(
-      const LocationTarget& location_target) const;
+  DeepestWindow AdjustTargetForModal(const DeepestWindow& target) const;
 
   void SetMouseCursorSourceWindow(ServerWindow* window);
 
@@ -235,21 +236,31 @@
   //   when no buttons on the mouse are down.
   // This also generates exit events as appropriate. For example, if the mouse
   // moves between one window to another an exit is generated on the first.
-  void ProcessPointerEventOnFoundTarget(
-      const ui::PointerEvent& event,
-      const LocationTarget& found_location_target);
+  void ProcessPointerEventOnFoundTarget(const ui::PointerEvent& event,
+                                        const DisplayLocation& display_location,
+                                        const DeepestWindow& found_target);
+
+  // Called when processing a pointer event to updated cursor related
+  // properties.
+  void UpdateCursorRelatedProperties(const ui::PointerEvent& event,
+                                     const DisplayLocation& display_location);
 
   void UpdateNonClientAreaForCurrentWindowOnFoundWindow(
-      const LocationTarget& found_location_target);
+      const DisplayLocation& display_location,
+      const DeepestWindow& target);
 
   // This callback is triggered by UpdateCursorProviderByLastKnownLocation().
   // It calls UpdateCursorProvider() as appropriate.
   void UpdateCursorProviderByLastKnownLocationOnFoundWindow(
-      const LocationTarget& location_target);
+      const DisplayLocation& display_location,
+      const DeepestWindow& target);
 
   // Immediatley updates the cursor provider (|mouse_cursor_source_window_|)
   // as appropriate.
-  void UpdateCursorProvider(const LocationTarget& location_target);
+  void UpdateCursorProvider(const DeepestWindow& target);
+
+  // Called during a click to nodify if the click was blocked by a modal.
+  void HandleClickOnBlockedWindow(const DeepestWindow& target);
 
   // Adds |pointer_target| to |pointer_targets_|.
   void StartTrackingPointer(int32_t pointer_id,
diff --git a/services/ui/ws/event_targeter.cc b/services/ui/ws/event_targeter.cc
index 1a586d5..e94346a 100644
--- a/services/ui/ws/event_targeter.cc
+++ b/services/ui/ws/event_targeter.cc
@@ -15,13 +15,12 @@
 namespace ui {
 namespace ws {
 
-EventTargeter::HitTestRequest::HitTestRequest(EventSource event_source,
-                                              const gfx::Point& location,
-                                              int64_t display_id,
-                                              HitTestCallback callback)
+EventTargeter::HitTestRequest::HitTestRequest(
+    EventSource event_source,
+    const DisplayLocation& display_location,
+    HitTestCallback callback)
     : event_source(event_source),
-      location(location),
-      display_id(display_id),
+      display_location(display_location),
       callback(std::move(callback)) {}
 
 EventTargeter::HitTestRequest::~HitTestRequest() {}
@@ -33,19 +32,19 @@
 
 EventTargeter::~EventTargeter() {}
 
-void EventTargeter::FindTargetForLocation(EventSource event_source,
-                                          const gfx::Point& location,
-                                          int64_t display_id,
-                                          HitTestCallback callback) {
+void EventTargeter::FindTargetForLocation(
+    EventSource event_source,
+    const DisplayLocation& display_location,
+    HitTestCallback callback) {
   if (IsHitTestInFlight()) {
     std::unique_ptr<HitTestRequest> hittest_request =
-        base::MakeUnique<HitTestRequest>(event_source, location, display_id,
+        base::MakeUnique<HitTestRequest>(event_source, display_location,
                                          std::move(callback));
     hit_test_request_queue_.push(std::move(hittest_request));
     return;
   }
 
-  ProcessFindTarget(event_source, location, display_id, std::move(callback));
+  ProcessFindTarget(event_source, display_location, std::move(callback));
 }
 
 bool EventTargeter::IsHitTestInFlight() const {
@@ -53,8 +52,7 @@
 }
 
 void EventTargeter::ProcessFindTarget(EventSource event_source,
-                                      const gfx::Point& location,
-                                      int64_t display_id,
+                                      const DisplayLocation& display_location,
                                       HitTestCallback callback) {
   // TODO(riajiang): After the async ask-client part is implemented, the async
   // part should be moved to after sync viz-hit-test call.
@@ -63,39 +61,36 @@
     DCHECK(!hit_test_in_flight_);
     hit_test_in_flight_ = true;
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE,
-        base::BindOnce(&EventTargeter::FindTargetForLocationNow,
-                       weak_ptr_factory_.GetWeakPtr(), event_source, location,
-                       display_id, base::Passed(&callback)));
+        FROM_HERE, base::BindOnce(&EventTargeter::FindTargetForLocationNow,
+                                  weak_ptr_factory_.GetWeakPtr(), event_source,
+                                  display_location, base::Passed(&callback)));
   } else {
-    FindTargetForLocationNow(event_source, location, display_id,
+    FindTargetForLocationNow(event_source, display_location,
                              std::move(callback));
   }
 }
 
-void EventTargeter::FindTargetForLocationNow(EventSource event_source,
-                                             const gfx::Point& location,
-                                             int64_t display_id,
-                                             HitTestCallback callback) {
-  LocationTarget location_target;
-  location_target.location_in_root = location;
-  location_target.display_id = display_id;
+void EventTargeter::FindTargetForLocationNow(
+    EventSource event_source,
+    const DisplayLocation& display_location,
+    HitTestCallback callback) {
+  DisplayLocation updated_display_location = display_location;
   ServerWindow* root = event_targeter_delegate_->GetRootWindowContaining(
-      &location_target.location_in_root, &location_target.display_id);
+      &updated_display_location.location, &updated_display_location.display_id);
+  DeepestWindow deepest_window;
   if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kUseVizHitTest)) {
     if (root) {
-      location_target.deepest_window =
-          ui::ws::FindDeepestVisibleWindowForLocation(
-              root, event_source, location_target.location_in_root);
+      deepest_window = ui::ws::FindDeepestVisibleWindowForLocation(
+          root, event_source, updated_display_location.location);
     }
   } else {
     viz::HitTestQuery* hit_test_query =
         event_targeter_delegate_->GetHitTestQueryForDisplay(
-            location_target.display_id);
+            updated_display_location.display_id);
     if (hit_test_query) {
       viz::Target target = hit_test_query->FindTargetForLocation(
-          location_target.location_in_root);
+          updated_display_location.location);
       if (target.frame_sink_id.is_valid()) {
         ServerWindow* target_window =
             event_targeter_delegate_->GetWindowFromFrameSinkId(
@@ -105,12 +100,12 @@
           // maybe a security fault. http://crbug.com/746470
           NOTREACHED();
         }
-        location_target.deepest_window.window = target_window;
-        location_target.location_in_target = target.location_in_target;
+        deepest_window.window = target_window;
+        // TODO(riajiang): use |target.location_in_target|.
       }
     }
   }
-  std::move(callback).Run(location_target);
+  std::move(callback).Run(updated_display_location, deepest_window);
   ProcessNextHitTestRequestFromQueue();
 }
 
@@ -124,8 +119,8 @@
   std::unique_ptr<HitTestRequest> hittest_request =
       std::move(hit_test_request_queue_.front());
   hit_test_request_queue_.pop();
-  ProcessFindTarget(hittest_request->event_source, hittest_request->location,
-                    hittest_request->display_id,
+  ProcessFindTarget(hittest_request->event_source,
+                    hittest_request->display_location,
                     std::move(hittest_request->callback));
 }
 
diff --git a/services/ui/ws/event_targeter.h b/services/ui/ws/event_targeter.h
index 96baae4..93e8199 100644
--- a/services/ui/ws/event_targeter.h
+++ b/services/ui/ws/event_targeter.h
@@ -19,18 +19,14 @@
 namespace ws {
 class EventTargeterDelegate;
 
-// The target |deepest_window| for a given location, locations and |display_id|
-// are associated with the display |deepest_window| is on. |location_in_root|
-// is the location in root window's coord-space while |location_in_target| is
-// the transformed location in the |deepest_window|'s coord-space.
-struct LocationTarget {
-  DeepestWindow deepest_window;
-  gfx::Point location_in_root;
-  gfx::Point location_in_target;
-  int64_t display_id = display::kInvalidDisplayId;
+// Contains a location relative to a particular display.
+struct DisplayLocation {
+  gfx::Point location;
+  int64_t display_id;
 };
 
-using HitTestCallback = base::OnceCallback<void(const LocationTarget&)>;
+using HitTestCallback =
+    base::OnceCallback<void(const DisplayLocation&, const DeepestWindow&)>;
 
 // Finds the target window for a location.
 class EventTargeter {
@@ -38,11 +34,10 @@
   explicit EventTargeter(EventTargeterDelegate* event_targeter_delegate);
   ~EventTargeter();
 
-  // Calls WindowFinder to find the target for |location|.
-  // |callback| is called with the LocationTarget found.
+  // Calls WindowFinder to find the target for |display_location|. |callback| is
+  // called with the found target.
   void FindTargetForLocation(EventSource event_source,
-                             const gfx::Point& location,
-                             int64_t display_id,
+                             const DisplayLocation& display_location,
                              HitTestCallback callback);
 
   bool IsHitTestInFlight() const;
@@ -50,25 +45,21 @@
  private:
   struct HitTestRequest {
     HitTestRequest(EventSource event_source,
-                   const gfx::Point& location,
-                   int64_t display_id,
+                   const DisplayLocation& display_location,
                    HitTestCallback hittest_callback);
     ~HitTestRequest();
 
     EventSource event_source;
-    gfx::Point location;
-    int64_t display_id;
+    DisplayLocation display_location;
     HitTestCallback callback;
   };
 
   void ProcessFindTarget(EventSource event_source,
-                         const gfx::Point& location,
-                         int64_t display_id,
+                         const DisplayLocation& display_location,
                          HitTestCallback callback);
 
   void FindTargetForLocationNow(EventSource event_source,
-                                const gfx::Point& location,
-                                int64_t display_id,
+                                const DisplayLocation& display_location,
                                 HitTestCallback callback);
 
   void ProcessNextHitTestRequestFromQueue();
diff --git a/services/ui/ws/window_tree.cc b/services/ui/ws/window_tree.cc
index 37ad796..41244a0 100644
--- a/services/ui/ws/window_tree.cc
+++ b/services/ui/ws/window_tree.cc
@@ -2411,11 +2411,11 @@
       display, TransportMetricsToDisplayMetrics(*viewport_metrics),
       is_primary_display, MakeClientWindowId(window_id));
   if (!display_root) {
-    callback.Run(base::nullopt);
+    callback.Run(false);
     return;
   }
   display_root->parent()->SetVisible(true);
-  callback.Run(display_root->current_local_surface_id());
+  callback.Run(true);
 }
 
 void WindowTree::SetDisplayConfiguration(
diff --git a/services/viz/public/cpp/compositing/BUILD.gn b/services/viz/public/cpp/compositing/BUILD.gn
index 979066b..c9f9613 100644
--- a/services/viz/public/cpp/compositing/BUILD.gn
+++ b/services/viz/public/cpp/compositing/BUILD.gn
@@ -17,6 +17,7 @@
     "//services/service_manager/public/cpp",
     "//services/service_manager/public/cpp:service_test_support",
     "//services/viz/public/interfaces",
+    "//skia/public/interfaces",
     "//testing/gtest",
     "//ui/gfx:test_support",
   ]
diff --git a/services/viz/public/cpp/compositing/DEPS b/services/viz/public/cpp/compositing/DEPS
index 1bd07606..ca53658 100644
--- a/services/viz/public/cpp/compositing/DEPS
+++ b/services/viz/public/cpp/compositing/DEPS
@@ -3,6 +3,7 @@
   "+gpu/ipc",
   "+gpu/ipc/common",
   "+skia/public/interfaces",
+  "+third_party/skia/include",
   "+ui/gfx",
   "+ui/latency/mojo",
 ]
diff --git a/services/viz/public/cpp/compositing/compositor_frame_for_blink.typemap b/services/viz/public/cpp/compositing/compositor_frame_for_blink.typemap
index 7d85b5c..ad979fe 100644
--- a/services/viz/public/cpp/compositing/compositor_frame_for_blink.typemap
+++ b/services/viz/public/cpp/compositing/compositor_frame_for_blink.typemap
@@ -5,8 +5,6 @@
 mojom = "//services/viz/public/interfaces/compositing/compositor_frame.mojom"
 public_headers = [ "//cc/output/compositor_frame.h" ]
 traits_headers = [
-  "//cc/ipc/filter_operation_struct_traits.h",
-  "//cc/ipc/filter_operations_struct_traits.h",
   "//gpu/ipc/common/mailbox_holder_struct_traits.h",
   "//gpu/ipc/common/mailbox_struct_traits.h",
   "//gpu/ipc/common/sync_token_struct_traits.h",
@@ -14,6 +12,8 @@
   "//mojo/common/common_custom_types_struct_traits.h",
   "//services/viz/public/cpp/compositing/compositor_frame_struct_traits.h",
   "//services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.h",
+  "//services/viz/public/cpp/compositing/filter_operation_struct_traits.h",
+  "//services/viz/public/cpp/compositing/filter_operations_struct_traits.h",
   "//services/viz/public/cpp/compositing/quads_struct_traits.h",
   "//services/viz/public/cpp/compositing/render_pass_struct_traits.h",
   "//services/viz/public/cpp/compositing/selection_struct_traits.h",
diff --git a/services/viz/public/cpp/compositing/filter_operation.typemap b/services/viz/public/cpp/compositing/filter_operation.typemap
new file mode 100644
index 0000000..f0cd91c
--- /dev/null
+++ b/services/viz/public/cpp/compositing/filter_operation.typemap
@@ -0,0 +1,9 @@
+# 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.
+
+mojom = "//services/viz/public/interfaces/compositing/filter_operation.mojom"
+public_headers = [ "//cc/base/filter_operation.h" ]
+traits_headers =
+    [ "//services/viz/public/cpp/compositing/filter_operation_struct_traits.h" ]
+type_mappings = [ "viz.mojom.FilterOperation=cc::FilterOperation" ]
diff --git a/cc/ipc/filter_operation_struct_traits.h b/services/viz/public/cpp/compositing/filter_operation_struct_traits.h
similarity index 75%
rename from cc/ipc/filter_operation_struct_traits.h
rename to services/viz/public/cpp/compositing/filter_operation_struct_traits.h
index 5deb0d7..63d2f70e 100644
--- a/cc/ipc/filter_operation_struct_traits.h
+++ b/services/viz/public/cpp/compositing/filter_operation_struct_traits.h
@@ -2,88 +2,88 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CC_IPC_FILTER_OPERATION_STRUCT_TRAITS_H_
-#define CC_IPC_FILTER_OPERATION_STRUCT_TRAITS_H_
+#ifndef SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_FILTER_OPERATION_STRUCT_TRAITS_H_
+#define SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_FILTER_OPERATION_STRUCT_TRAITS_H_
 
 #include "base/containers/span.h"
 #include "cc/base/filter_operation.h"
-#include "cc/ipc/filter_operation.mojom-shared.h"
+#include "services/viz/public/interfaces/compositing/filter_operation.mojom-shared.h"
 #include "skia/public/interfaces/blur_image_filter_tile_mode_struct_traits.h"
 #include "skia/public/interfaces/image_filter_struct_traits.h"
 
 namespace mojo {
 
 namespace {
-cc::mojom::FilterType CCFilterTypeToMojo(
+viz::mojom::FilterType CCFilterTypeToMojo(
     const cc::FilterOperation::FilterType& type) {
   switch (type) {
     case cc::FilterOperation::GRAYSCALE:
-      return cc::mojom::FilterType::GRAYSCALE;
+      return viz::mojom::FilterType::GRAYSCALE;
     case cc::FilterOperation::SEPIA:
-      return cc::mojom::FilterType::SEPIA;
+      return viz::mojom::FilterType::SEPIA;
     case cc::FilterOperation::SATURATE:
-      return cc::mojom::FilterType::SATURATE;
+      return viz::mojom::FilterType::SATURATE;
     case cc::FilterOperation::HUE_ROTATE:
-      return cc::mojom::FilterType::HUE_ROTATE;
+      return viz::mojom::FilterType::HUE_ROTATE;
     case cc::FilterOperation::INVERT:
-      return cc::mojom::FilterType::INVERT;
+      return viz::mojom::FilterType::INVERT;
     case cc::FilterOperation::BRIGHTNESS:
-      return cc::mojom::FilterType::BRIGHTNESS;
+      return viz::mojom::FilterType::BRIGHTNESS;
     case cc::FilterOperation::CONTRAST:
-      return cc::mojom::FilterType::CONTRAST;
+      return viz::mojom::FilterType::CONTRAST;
     case cc::FilterOperation::OPACITY:
-      return cc::mojom::FilterType::OPACITY;
+      return viz::mojom::FilterType::OPACITY;
     case cc::FilterOperation::BLUR:
-      return cc::mojom::FilterType::BLUR;
+      return viz::mojom::FilterType::BLUR;
     case cc::FilterOperation::DROP_SHADOW:
-      return cc::mojom::FilterType::DROP_SHADOW;
+      return viz::mojom::FilterType::DROP_SHADOW;
     case cc::FilterOperation::COLOR_MATRIX:
-      return cc::mojom::FilterType::COLOR_MATRIX;
+      return viz::mojom::FilterType::COLOR_MATRIX;
     case cc::FilterOperation::ZOOM:
-      return cc::mojom::FilterType::ZOOM;
+      return viz::mojom::FilterType::ZOOM;
     case cc::FilterOperation::REFERENCE:
-      return cc::mojom::FilterType::REFERENCE;
+      return viz::mojom::FilterType::REFERENCE;
     case cc::FilterOperation::SATURATING_BRIGHTNESS:
-      return cc::mojom::FilterType::SATURATING_BRIGHTNESS;
+      return viz::mojom::FilterType::SATURATING_BRIGHTNESS;
     case cc::FilterOperation::ALPHA_THRESHOLD:
-      return cc::mojom::FilterType::ALPHA_THRESHOLD;
+      return viz::mojom::FilterType::ALPHA_THRESHOLD;
   }
   NOTREACHED();
-  return cc::mojom::FilterType::FILTER_TYPE_LAST;
+  return viz::mojom::FilterType::FILTER_TYPE_LAST;
 }
 
 cc::FilterOperation::FilterType MojoFilterTypeToCC(
-    const cc::mojom::FilterType& type) {
+    const viz::mojom::FilterType& type) {
   switch (type) {
-    case cc::mojom::FilterType::GRAYSCALE:
+    case viz::mojom::FilterType::GRAYSCALE:
       return cc::FilterOperation::GRAYSCALE;
-    case cc::mojom::FilterType::SEPIA:
+    case viz::mojom::FilterType::SEPIA:
       return cc::FilterOperation::SEPIA;
-    case cc::mojom::FilterType::SATURATE:
+    case viz::mojom::FilterType::SATURATE:
       return cc::FilterOperation::SATURATE;
-    case cc::mojom::FilterType::HUE_ROTATE:
+    case viz::mojom::FilterType::HUE_ROTATE:
       return cc::FilterOperation::HUE_ROTATE;
-    case cc::mojom::FilterType::INVERT:
+    case viz::mojom::FilterType::INVERT:
       return cc::FilterOperation::INVERT;
-    case cc::mojom::FilterType::BRIGHTNESS:
+    case viz::mojom::FilterType::BRIGHTNESS:
       return cc::FilterOperation::BRIGHTNESS;
-    case cc::mojom::FilterType::CONTRAST:
+    case viz::mojom::FilterType::CONTRAST:
       return cc::FilterOperation::CONTRAST;
-    case cc::mojom::FilterType::OPACITY:
+    case viz::mojom::FilterType::OPACITY:
       return cc::FilterOperation::OPACITY;
-    case cc::mojom::FilterType::BLUR:
+    case viz::mojom::FilterType::BLUR:
       return cc::FilterOperation::BLUR;
-    case cc::mojom::FilterType::DROP_SHADOW:
+    case viz::mojom::FilterType::DROP_SHADOW:
       return cc::FilterOperation::DROP_SHADOW;
-    case cc::mojom::FilterType::COLOR_MATRIX:
+    case viz::mojom::FilterType::COLOR_MATRIX:
       return cc::FilterOperation::COLOR_MATRIX;
-    case cc::mojom::FilterType::ZOOM:
+    case viz::mojom::FilterType::ZOOM:
       return cc::FilterOperation::ZOOM;
-    case cc::mojom::FilterType::REFERENCE:
+    case viz::mojom::FilterType::REFERENCE:
       return cc::FilterOperation::REFERENCE;
-    case cc::mojom::FilterType::SATURATING_BRIGHTNESS:
+    case viz::mojom::FilterType::SATURATING_BRIGHTNESS:
       return cc::FilterOperation::SATURATING_BRIGHTNESS;
-    case cc::mojom::FilterType::ALPHA_THRESHOLD:
+    case viz::mojom::FilterType::ALPHA_THRESHOLD:
       return cc::FilterOperation::ALPHA_THRESHOLD;
   }
   NOTREACHED();
@@ -93,8 +93,8 @@
 }  // namespace
 
 template <>
-struct StructTraits<cc::mojom::FilterOperationDataView, cc::FilterOperation> {
-  static cc::mojom::FilterType type(const cc::FilterOperation& op) {
+struct StructTraits<viz::mojom::FilterOperationDataView, cc::FilterOperation> {
+  static viz::mojom::FilterType type(const cc::FilterOperation& op) {
     return CCFilterTypeToMojo(op.type());
   }
 
@@ -158,7 +158,7 @@
         ToMojom(operation.blur_tile_mode());
   }
 
-  static bool Read(cc::mojom::FilterOperationDataView data,
+  static bool Read(viz::mojom::FilterOperationDataView data,
                    cc::FilterOperation* out) {
     out->set_type(MojoFilterTypeToCC(data.type()));
     switch (out->type()) {
@@ -228,4 +228,4 @@
 
 }  // namespace mojo
 
-#endif  // CC_IPC_FILTER_OPERATION_STRUCT_TRAITS_H_
+#endif  // SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_FILTER_OPERATION_STRUCT_TRAITS_H_
diff --git a/services/viz/public/cpp/compositing/filter_operations.typemap b/services/viz/public/cpp/compositing/filter_operations.typemap
new file mode 100644
index 0000000..f9179bd
--- /dev/null
+++ b/services/viz/public/cpp/compositing/filter_operations.typemap
@@ -0,0 +1,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.
+
+mojom = "//services/viz/public/interfaces/compositing/filter_operations.mojom"
+public_headers = [ "//cc/base/filter_operations.h" ]
+traits_headers = [ "//services/viz/public/cpp/compositing/filter_operations_struct_traits.h" ]
+type_mappings = [ "viz.mojom.FilterOperations=cc::FilterOperations" ]
diff --git a/services/viz/public/cpp/compositing/filter_operations_struct_traits.h b/services/viz/public/cpp/compositing/filter_operations_struct_traits.h
new file mode 100644
index 0000000..4b6a573
--- /dev/null
+++ b/services/viz/public/cpp/compositing/filter_operations_struct_traits.h
@@ -0,0 +1,33 @@
+// 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 SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_FILTER_OPERATIONS_STRUCT_TRAITS_H_
+#define SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_FILTER_OPERATIONS_STRUCT_TRAITS_H_
+
+#include "cc/base/filter_operations.h"
+#include "services/viz/public/interfaces/compositing/filter_operations.mojom-shared.h"
+
+namespace mojo {
+
+template <>
+struct StructTraits<viz::mojom::FilterOperationsDataView,
+                    cc::FilterOperations> {
+  static const std::vector<cc::FilterOperation>& operations(
+      const cc::FilterOperations& operations) {
+    return operations.operations();
+  }
+
+  static bool Read(viz::mojom::FilterOperationsDataView data,
+                   cc::FilterOperations* out) {
+    std::vector<cc::FilterOperation> operations;
+    if (!data.ReadOperations(&operations))
+      return false;
+    *out = cc::FilterOperations(std::move(operations));
+    return true;
+  }
+};
+
+}  // namespace mojo
+
+#endif  // SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_FILTER_OPERATIONS_STRUCT_TRAITS_H_
diff --git a/services/viz/public/cpp/compositing/quads_struct_traits.h b/services/viz/public/cpp/compositing/quads_struct_traits.h
index 97e1153..f81ecbf 100644
--- a/services/viz/public/cpp/compositing/quads_struct_traits.h
+++ b/services/viz/public/cpp/compositing/quads_struct_traits.h
@@ -7,8 +7,6 @@
 
 #include "base/containers/span.h"
 #include "base/logging.h"
-#include "cc/ipc/filter_operation_struct_traits.h"
-#include "cc/ipc/filter_operations_struct_traits.h"
 #include "cc/quads/debug_border_draw_quad.h"
 #include "cc/quads/picture_draw_quad.h"
 #include "cc/quads/render_pass_draw_quad.h"
@@ -18,6 +16,8 @@
 #include "cc/quads/texture_draw_quad.h"
 #include "cc/quads/tile_draw_quad.h"
 #include "cc/quads/yuv_video_draw_quad.h"
+#include "services/viz/public/cpp/compositing/filter_operation_struct_traits.h"
+#include "services/viz/public/cpp/compositing/filter_operations_struct_traits.h"
 #include "services/viz/public/cpp/compositing/shared_quad_state_struct_traits.h"
 #include "services/viz/public/cpp/compositing/surface_id_struct_traits.h"
 #include "services/viz/public/interfaces/compositing/quads.mojom-shared.h"
diff --git a/services/viz/public/cpp/compositing/struct_traits_unittest.cc b/services/viz/public/cpp/compositing/struct_traits_unittest.cc
index 73df7ec..1427cfb8 100644
--- a/services/viz/public/cpp/compositing/struct_traits_unittest.cc
+++ b/services/viz/public/cpp/compositing/struct_traits_unittest.cc
@@ -7,8 +7,6 @@
 #include "base/message_loop/message_loop.h"
 #include "cc/ipc/copy_output_request_struct_traits.h"
 #include "cc/ipc/copy_output_result_struct_traits.h"
-#include "cc/ipc/filter_operation_struct_traits.h"
-#include "cc/ipc/filter_operations_struct_traits.h"
 #include "cc/ipc/frame_sink_id_struct_traits.h"
 #include "cc/ipc/local_surface_id_struct_traits.h"
 #include "cc/ipc/texture_mailbox_struct_traits.h"
@@ -32,6 +30,8 @@
 #include "services/viz/public/cpp/compositing/begin_frame_args_struct_traits.h"
 #include "services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.h"
 #include "services/viz/public/cpp/compositing/compositor_frame_struct_traits.h"
+#include "services/viz/public/cpp/compositing/filter_operation_struct_traits.h"
+#include "services/viz/public/cpp/compositing/filter_operations_struct_traits.h"
 #include "services/viz/public/cpp/compositing/render_pass_struct_traits.h"
 #include "services/viz/public/cpp/compositing/resource_settings_struct_traits.h"
 #include "services/viz/public/cpp/compositing/returned_resource_struct_traits.h"
@@ -43,6 +43,8 @@
 #include "services/viz/public/cpp/compositing/transferable_resource_struct_traits.h"
 #include "services/viz/public/interfaces/compositing/begin_frame_args.mojom.h"
 #include "services/viz/public/interfaces/compositing/compositor_frame.mojom.h"
+#include "services/viz/public/interfaces/compositing/filter_operation.mojom.h"
+#include "services/viz/public/interfaces/compositing/filter_operations.mojom.h"
 #include "services/viz/public/interfaces/compositing/returned_resource.mojom.h"
 #include "services/viz/public/interfaces/compositing/surface_info.mojom.h"
 #include "services/viz/public/interfaces/compositing/surface_sequence.mojom.h"
@@ -51,6 +53,8 @@
 #include "skia/public/interfaces/blur_image_filter_tile_mode_struct_traits.h"
 #include "skia/public/interfaces/image_filter_struct_traits.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkString.h"
+#include "third_party/skia/include/effects/SkDropShadowImageFilter.h"
 #include "ui/gfx/geometry/mojo/geometry_struct_traits.h"
 #include "ui/gfx/ipc/color/gfx_param_traits.h"
 #include "ui/gfx/mojo/buffer_types_struct_traits.h"
@@ -127,6 +131,97 @@
   EXPECT_FALSE(output.has_damage);
 }
 
+namespace {
+
+void ExpectEqual(const cc::FilterOperation& input,
+                 const cc::FilterOperation& output) {
+  EXPECT_EQ(input.type(), output.type());
+  switch (input.type()) {
+    case cc::FilterOperation::GRAYSCALE:
+    case cc::FilterOperation::SEPIA:
+    case cc::FilterOperation::SATURATE:
+    case cc::FilterOperation::HUE_ROTATE:
+    case cc::FilterOperation::INVERT:
+    case cc::FilterOperation::BRIGHTNESS:
+    case cc::FilterOperation::SATURATING_BRIGHTNESS:
+    case cc::FilterOperation::CONTRAST:
+    case cc::FilterOperation::OPACITY:
+    case cc::FilterOperation::BLUR:
+      EXPECT_EQ(input.amount(), output.amount());
+      break;
+    case cc::FilterOperation::DROP_SHADOW:
+      EXPECT_EQ(input.amount(), output.amount());
+      EXPECT_EQ(input.drop_shadow_offset(), output.drop_shadow_offset());
+      EXPECT_EQ(input.drop_shadow_color(), output.drop_shadow_color());
+      break;
+    case cc::FilterOperation::COLOR_MATRIX:
+      EXPECT_EQ(0, memcmp(input.matrix(), output.matrix(), 20));
+      break;
+    case cc::FilterOperation::ZOOM:
+      EXPECT_EQ(input.amount(), output.amount());
+      EXPECT_EQ(input.zoom_inset(), output.zoom_inset());
+      break;
+    case cc::FilterOperation::REFERENCE: {
+      SkString input_str;
+      input.image_filter()->toString(&input_str);
+      SkString output_str;
+      output.image_filter()->toString(&output_str);
+      EXPECT_EQ(input_str, output_str);
+      break;
+    }
+    case cc::FilterOperation::ALPHA_THRESHOLD:
+      NOTREACHED();
+      break;
+  }
+}
+
+}  // namespace
+
+TEST_F(StructTraitsTest, FilterOperationBlur) {
+  cc::FilterOperation input = cc::FilterOperation::CreateBlurFilter(20);
+
+  cc::FilterOperation output;
+  SerializeAndDeserialize<mojom::FilterOperation>(input, &output);
+  ExpectEqual(input, output);
+}
+
+TEST_F(StructTraitsTest, FilterOperationDropShadow) {
+  cc::FilterOperation input = cc::FilterOperation::CreateDropShadowFilter(
+      gfx::Point(4, 4), 4.0f, SkColorSetARGB(255, 40, 0, 0));
+
+  cc::FilterOperation output;
+  SerializeAndDeserialize<mojom::FilterOperation>(input, &output);
+  ExpectEqual(input, output);
+}
+
+TEST_F(StructTraitsTest, FilterOperationReferenceFilter) {
+  cc::FilterOperation input =
+      cc::FilterOperation::CreateReferenceFilter(SkDropShadowImageFilter::Make(
+          SkIntToScalar(3), SkIntToScalar(8), SkIntToScalar(4),
+          SkIntToScalar(9), SK_ColorBLACK,
+          SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
+          nullptr));
+
+  cc::FilterOperation output;
+  SerializeAndDeserialize<mojom::FilterOperation>(input, &output);
+  ExpectEqual(input, output);
+}
+
+TEST_F(StructTraitsTest, FilterOperations) {
+  cc::FilterOperations input;
+  input.Append(cc::FilterOperation::CreateBlurFilter(0.f));
+  input.Append(cc::FilterOperation::CreateSaturateFilter(4.f));
+  input.Append(cc::FilterOperation::CreateZoomFilter(2.0f, 1));
+
+  cc::FilterOperations output;
+  SerializeAndDeserialize<mojom::FilterOperations>(input, &output);
+
+  EXPECT_EQ(input.size(), output.size());
+  for (size_t i = 0; i < input.size(); ++i) {
+    ExpectEqual(input.at(i), output.at(i));
+  }
+}
+
 TEST_F(StructTraitsTest, ResourceSettings) {
   constexpr size_t kArbitrarySize = 32;
   constexpr bool kArbitraryBool = true;
diff --git a/services/viz/public/cpp/compositing/typemaps.gni b/services/viz/public/cpp/compositing/typemaps.gni
index fdec0b44..4603cbc 100644
--- a/services/viz/public/cpp/compositing/typemaps.gni
+++ b/services/viz/public/cpp/compositing/typemaps.gni
@@ -6,6 +6,8 @@
   "//services/viz/public/cpp/compositing/begin_frame_args.typemap",
   "//services/viz/public/cpp/compositing/compositor_frame.typemap",
   "//services/viz/public/cpp/compositing/compositor_frame_metadata.typemap",
+  "//services/viz/public/cpp/compositing/filter_operation.typemap",
+  "//services/viz/public/cpp/compositing/filter_operations.typemap",
   "//services/viz/public/cpp/compositing/render_pass.typemap",
   "//services/viz/public/cpp/compositing/resource_settings.typemap",
   "//services/viz/public/cpp/compositing/returned_resource.typemap",
diff --git a/services/viz/public/interfaces/BUILD.gn b/services/viz/public/interfaces/BUILD.gn
index 5a52eaa0..00814e5 100644
--- a/services/viz/public/interfaces/BUILD.gn
+++ b/services/viz/public/interfaces/BUILD.gn
@@ -10,6 +10,8 @@
     "compositing/compositor_frame.mojom",
     "compositing/compositor_frame_metadata.mojom",
     "compositing/compositor_frame_sink.mojom",
+    "compositing/filter_operation.mojom",
+    "compositing/filter_operations.mojom",
     "compositing/quads.mojom",
     "compositing/render_pass.mojom",
     "compositing/resource_settings.mojom",
@@ -28,6 +30,7 @@
     "//cc/ipc:interfaces",
     "//gpu/ipc/common:interfaces",
     "//mojo/common:common_custom_types",
+    "//skia/public/interfaces",
     "//ui/gfx/geometry/mojo",
     "//ui/gfx/mojo",
     "//ui/latency/mojo:interfaces",
diff --git a/cc/ipc/filter_operation.mojom b/services/viz/public/interfaces/compositing/filter_operation.mojom
similarity index 97%
rename from cc/ipc/filter_operation.mojom
rename to services/viz/public/interfaces/compositing/filter_operation.mojom
index e0cbd132..ee6c87d 100644
--- a/cc/ipc/filter_operation.mojom
+++ b/services/viz/public/interfaces/compositing/filter_operation.mojom
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-module cc.mojom;
+module viz.mojom;
 
 import "skia/public/interfaces/image_filter.mojom";
 import "skia/public/interfaces/blur_image_filter_tile_mode.mojom";
diff --git a/cc/ipc/filter_operations.mojom b/services/viz/public/interfaces/compositing/filter_operations.mojom
similarity index 63%
rename from cc/ipc/filter_operations.mojom
rename to services/viz/public/interfaces/compositing/filter_operations.mojom
index 6e62890f..16b05df 100644
--- a/cc/ipc/filter_operations.mojom
+++ b/services/viz/public/interfaces/compositing/filter_operations.mojom
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-module cc.mojom;
+module viz.mojom;
 
-import "cc/ipc/filter_operation.mojom";
+import "services/viz/public/interfaces/compositing/filter_operation.mojom";
 
 // See cc/base/filter_operations.h.
 struct FilterOperations {
-  array<cc.mojom.FilterOperation> operations;
+  array<FilterOperation> operations;
 };
 
diff --git a/services/viz/public/interfaces/compositing/render_pass.mojom b/services/viz/public/interfaces/compositing/render_pass.mojom
index a512e820..c983ae3 100644
--- a/services/viz/public/interfaces/compositing/render_pass.mojom
+++ b/services/viz/public/interfaces/compositing/render_pass.mojom
@@ -4,7 +4,7 @@
 
 module viz.mojom;
 
-import "cc/ipc/filter_operations.mojom";
+import "services/viz/public/interfaces/compositing/filter_operations.mojom";
 import "services/viz/public/interfaces/compositing/quads.mojom";
 import "ui/gfx/geometry/mojo/geometry.mojom";
 import "ui/gfx/mojo/color_space.mojom";
@@ -16,8 +16,8 @@
   gfx.mojom.Rect output_rect;
   gfx.mojom.Rect damage_rect;
   gfx.mojom.Transform transform_to_root_target;
-  cc.mojom.FilterOperations filters;
-  cc.mojom.FilterOperations background_filters;
+  FilterOperations filters;
+  FilterOperations background_filters;
   gfx.mojom.ColorSpace color_space;
   bool has_transparent_background;
   bool cache_render_pass = false;
diff --git a/services/viz/public/interfaces/hit_test/hit_test_region_list.mojom b/services/viz/public/interfaces/hit_test/hit_test_region_list.mojom
index ebe3b9b..124d8be 100644
--- a/services/viz/public/interfaces/hit_test/hit_test_region_list.mojom
+++ b/services/viz/public/interfaces/hit_test/hit_test_region_list.mojom
@@ -5,6 +5,7 @@
 module viz.mojom;
 
 import "cc/ipc/frame_sink_id.mojom";
+import "cc/ipc/local_surface_id.mojom";
 import "services/viz/public/interfaces/compositing/surface_id.mojom";
 import "ui/gfx/geometry/mojo/geometry.mojom";
 import "ui/gfx/mojo/transform.mojom";
@@ -33,11 +34,11 @@
   // Flags to indicate the type of HitTestRegion.
   uint32 flags;
 
-  // FrameSinkId is required when flags = kHitTestMine.
+  // FrameSinkId of this region.
   cc.mojom.FrameSinkId frame_sink_id;
 
-  // SurfaceId is required when flags = kHitTestChildSurface.
-  SurfaceId surface_id;
+  // LocalSurfaceId is required when flags include kHitTestChildSurface.
+  cc.mojom.LocalSurfaceId? local_surface_id;
 
   // The rect of the region in the coordinate space of the embedder.
   gfx.mojom.Rect rect;
diff --git a/skia/BUILD.gn b/skia/BUILD.gn
index 9675167c..beb166e 100644
--- a/skia/BUILD.gn
+++ b/skia/BUILD.gn
@@ -227,8 +227,6 @@
     "ext/event_tracer_impl.h",
     "ext/fontmgr_default_android.cc",
     "ext/fontmgr_default_android.h",
-    "ext/fontmgr_default_fuchsia.cc",
-    "ext/fontmgr_default_fuchsia.h",
     "ext/fontmgr_default_linux.cc",
     "ext/fontmgr_default_linux.h",
     "ext/fontmgr_default_win.cc",
@@ -274,13 +272,6 @@
     ]
   }
 
-  if (!is_fuchsia) {
-    sources -= [
-      "ext/fontmgr_default_fuchsia.cc",
-      "ext/fontmgr_default_fuchsia.h",
-    ]
-  }
-
   # The imported Skia gni source paths are made absolute by gn.
   sources += skia_core_sources
   sources += skia_effects_sources
@@ -439,6 +430,14 @@
     ]
   }
 
+  if (is_fuchsia) {
+    sources += [
+      "//third_party/skia/src/ports/SkFontMgr_custom.cpp",
+      "//third_party/skia/src/ports/SkFontMgr_custom_empty.cpp",
+      "//third_party/skia/src/ports/SkFontMgr_custom_empty_factory.cpp",
+    ]
+  }
+
   if (is_win) {
     sources += [
       # Select the right BitmapPlatformDevice.
diff --git a/skia/ext/fontmgr_default_fuchsia.cc b/skia/ext/fontmgr_default_fuchsia.cc
deleted file mode 100644
index 06c583ef..0000000
--- a/skia/ext/fontmgr_default_fuchsia.cc
+++ /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.
-
-#include "skia/ext/fontmgr_default_fuchsia.h"
-
-#include "third_party/skia/include/ports/SkFontMgr.h"
-#include "third_party/skia/include/ports/SkFontMgr_android.h"
-
-namespace {
-// An owning leaky bare pointer.
-SkFontMgr* g_default_fontmgr = nullptr;
-}  // namespace
-
-SK_API void SetDefaultSkiaFactory(sk_sp<SkFontMgr> fontmgr) {
-  SkASSERT(g_default_fontmgr == nullptr);
-  g_default_fontmgr = fontmgr.release();
-}
-
-SK_API sk_sp<SkFontMgr> SkFontMgr::Factory() {
-  // TODO(fuchsia): Implement SkFontMgr.
-  return g_default_fontmgr ? sk_ref_sp(g_default_fontmgr) : nullptr;
-}
diff --git a/skia/ext/fontmgr_default_fuchsia.h b/skia/ext/fontmgr_default_fuchsia.h
deleted file mode 100644
index a7a8e3a..0000000
--- a/skia/ext/fontmgr_default_fuchsia.h
+++ /dev/null
@@ -1,16 +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 SKIA_EXT_FONTMGR_DEFAULT_FUCHSIA_H_
-#define SKIA_EXT_FONTMGR_DEFAULT_FUCHSIA_H_
-
-#include "third_party/skia/include/core/SkTypes.h"
-
-class SkFontMgr;
-template <typename T>
-class sk_sp;
-
-SK_API void SetDefaultSkiaFactory(sk_sp<SkFontMgr> fontmgr);
-
-#endif  // SKIA_EXT_FONTMGR_DEFAULT_FUCHSIA_H_
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json
index 20dd49d4..f926a66 100644
--- a/testing/buildbot/chromium.android.fyi.json
+++ b/testing/buildbot/chromium.android.fyi.json
@@ -2,6 +2,15 @@
   "Android Cronet ARMv6 Builder": {
     "gtest_tests": [
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "cronet_sample_test_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -33,6 +42,15 @@
         "test": "cronet_sample_test_apk"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "cronet_smoketests_missing_native_library_instrumentation_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -64,6 +82,15 @@
         "test": "cronet_smoketests_missing_native_library_instrumentation_apk"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "cronet_smoketests_platform_only_instrumentation_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -95,6 +122,15 @@
         "test": "cronet_smoketests_platform_only_instrumentation_apk"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "cronet_test_instrumentation_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -127,6 +163,15 @@
         "test": "cronet_test_instrumentation_apk"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "cronet_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -158,6 +203,15 @@
         "test": "cronet_unittests"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "net_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -188,11 +242,33 @@
         },
         "test": "net_unittests"
       }
+    ],
+    "scripts": [
+      {
+        "args": [
+          "--platform",
+          "android-cronet",
+          "--perf-id",
+          "android_cronet_armv6_builder",
+          "cronet-armv6/sizes"
+        ],
+        "name": "sizes",
+        "script": "sizes.py"
+      }
     ]
   },
   "Android Cronet Builder (dbg)": {
     "gtest_tests": [
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "cronet_sample_test_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -224,6 +300,15 @@
         "test": "cronet_sample_test_apk"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "cronet_smoketests_missing_native_library_instrumentation_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -255,6 +340,15 @@
         "test": "cronet_smoketests_missing_native_library_instrumentation_apk"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "cronet_smoketests_platform_only_instrumentation_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -286,6 +380,15 @@
         "test": "cronet_smoketests_platform_only_instrumentation_apk"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "cronet_test_instrumentation_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -318,6 +421,15 @@
         "test": "cronet_test_instrumentation_apk"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "cronet_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -349,6 +461,15 @@
         "test": "cronet_unittests"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "net_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -424,6 +545,15 @@
   "Android Cronet KitKat Builder": {
     "gtest_tests": [
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "cronet_sample_test_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -455,6 +585,15 @@
         "test": "cronet_sample_test_apk"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "cronet_smoketests_missing_native_library_instrumentation_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -486,6 +625,15 @@
         "test": "cronet_smoketests_missing_native_library_instrumentation_apk"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "cronet_smoketests_platform_only_instrumentation_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -517,6 +665,15 @@
         "test": "cronet_smoketests_platform_only_instrumentation_apk"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "cronet_test_instrumentation_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -549,6 +706,15 @@
         "test": "cronet_test_instrumentation_apk"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "cronet_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -580,6 +746,15 @@
         "test": "cronet_unittests"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "net_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -610,6 +785,19 @@
         },
         "test": "net_unittests"
       }
+    ],
+    "scripts": [
+      {
+        "args": [
+          "--platform",
+          "android-cronet",
+          "--perf-id",
+          "android_cronet_builder",
+          "cronet-arm/sizes"
+        ],
+        "name": "sizes",
+        "script": "sizes.py"
+      }
     ]
   },
   "Android Tests (trial)(dbg)": {
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index 60433e5..aa8c4f2 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -2357,6 +2357,15 @@
         "test": "android_webview_unittests"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "base_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2512,6 +2521,15 @@
         "test": "cc_unittests"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "chrome_public_test_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2545,6 +2563,15 @@
         "test": "chrome_public_test_apk"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "chrome_sync_shell_test_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2577,6 +2604,15 @@
         "test": "chrome_sync_shell_test_apk"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "components_browsertests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2609,6 +2645,15 @@
         "test": "components_browsertests"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "components_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2642,6 +2687,15 @@
         "test": "components_unittests"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "content_browsertests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2675,6 +2729,15 @@
         "test": "content_browsertests"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "content_shell_test_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -2708,6 +2771,15 @@
         "test": "content_shell_test_apk"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "content_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -3150,6 +3222,15 @@
         "test": "media_unittests"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "net_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -3429,6 +3510,15 @@
         "test": "ui_touch_selection_unittests"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "unit_tests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -3462,6 +3552,15 @@
         "test": "unit_tests"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "viz_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -3535,6 +3634,15 @@
         "test": "vr_common_unittests"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "webview_instrumentation_test_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -3736,6 +3844,15 @@
         "test": "capture_unittests"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "cc_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -3851,6 +3968,15 @@
         "test": "components_unittests"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "content_browsertests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -4376,6 +4502,15 @@
         "test": "media_unittests"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "net_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -4655,6 +4790,15 @@
         "test": "ui_touch_selection_unittests"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "unit_tests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -4688,6 +4832,15 @@
         "test": "unit_tests"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "viz_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -4761,6 +4914,15 @@
         "test": "vr_common_unittests"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "chrome_public_test_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -4881,6 +5043,15 @@
         "test": "chrome_sync_shell_test_apk"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "content_shell_test_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -4914,6 +5085,15 @@
         "test": "content_shell_test_apk"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "webview_instrumentation_test_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -5156,6 +5336,15 @@
         "test": "cc_unittests"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "chrome_public_test_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -5189,6 +5378,15 @@
         "test": "chrome_public_test_apk"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "chrome_sync_shell_test_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -5221,6 +5419,15 @@
         "test": "chrome_sync_shell_test_apk"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "components_browsertests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -5253,6 +5460,15 @@
         "test": "components_browsertests"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "components_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -5286,6 +5502,15 @@
         "test": "components_unittests"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "content_browsertests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -5319,6 +5544,15 @@
         "test": "content_browsertests"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "content_shell_test_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -5352,6 +5586,15 @@
         "test": "content_shell_test_apk"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "content_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -5794,6 +6037,15 @@
         "test": "media_unittests"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "net_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -6073,6 +6325,15 @@
         "test": "ui_touch_selection_unittests"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "unit_tests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -6106,6 +6367,15 @@
         "test": "unit_tests"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "viz_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -6179,6 +6449,15 @@
         "test": "vr_common_unittests"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "webview_instrumentation_test_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -6419,6 +6698,15 @@
         "test": "capture_unittests"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "cc_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -7867,6 +8155,15 @@
         "test": "unit_tests"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "viz_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -8231,6 +8528,15 @@
         "test": "cc_unittests"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "chrome_public_test_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -8264,6 +8570,15 @@
         "test": "chrome_public_test_apk"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "chrome_sync_shell_test_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -8296,6 +8611,15 @@
         "test": "chrome_sync_shell_test_apk"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "components_browsertests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -8328,6 +8652,15 @@
         "test": "components_browsertests"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "components_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -8361,6 +8694,15 @@
         "test": "components_unittests"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "content_browsertests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -8394,6 +8736,15 @@
         "test": "content_browsertests"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "content_shell_test_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -8427,6 +8778,15 @@
         "test": "content_shell_test_apk"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "content_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -8869,6 +9229,15 @@
         "test": "media_unittests"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "net_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -9148,6 +9517,15 @@
         "test": "ui_touch_selection_unittests"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "unit_tests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -9181,6 +9559,15 @@
         "test": "unit_tests"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "viz_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -9254,6 +9641,15 @@
         "test": "vr_common_unittests"
       },
       {
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "webview_instrumentation_test_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
diff --git a/testing/buildbot/chromium.perf.fyi.json b/testing/buildbot/chromium.perf.fyi.json
index d153304..89ed35a 100644
--- a/testing/buildbot/chromium.perf.fyi.json
+++ b/testing/buildbot/chromium.perf.fyi.json
@@ -1,6 +1,31 @@
 {
   "AAAAA1 AUTOGENERATED FILE DO NOT EDIT": {},
   "AAAAA2 See //tools/perf/generate_perf_data to make changes": {},
+  "Histogram Pipeline Linux Perf": {
+    "isolated_scripts": [
+      {
+        "args": [
+          "dummy_benchmark.histogram_benchmark_1",
+          "-v",
+          "--upload-results",
+          "--output-format=histograms",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "dummy_benchmark.histogram_benchmark_1",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      }
+    ]
+  },
   "Mojo Linux Perf": {
     "isolated_scripts": [
       {
@@ -1296,7 +1321,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": false,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -1328,7 +1353,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": true,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -6043,7 +6068,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": false,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -6075,7 +6100,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": true,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
diff --git a/testing/buildbot/chromium.perf.json b/testing/buildbot/chromium.perf.json
index fb6f485..de2b8114 100644
--- a/testing/buildbot/chromium.perf.json
+++ b/testing/buildbot/chromium.perf.json
@@ -1254,7 +1254,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": false,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -1286,7 +1286,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": true,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -6290,7 +6290,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": false,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -6322,7 +6322,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": true,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -10748,7 +10748,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": false,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -13800,7 +13800,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": false,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -13832,7 +13832,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": true,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -18289,7 +18289,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": false,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -21341,7 +21341,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": false,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -21373,7 +21373,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": true,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -26253,7 +26253,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": false,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -26285,7 +26285,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": true,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -31335,7 +31335,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": false,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -31367,7 +31367,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": true,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -36289,7 +36289,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": false,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -36321,7 +36321,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": true,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -41242,7 +41242,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": false,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -41274,7 +41274,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": true,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -46195,7 +46195,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": false,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -46227,7 +46227,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": true,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -51148,7 +51148,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": false,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -51180,7 +51180,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": true,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -56080,7 +56080,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": false,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -56112,7 +56112,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": true,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -61033,7 +61033,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": false,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -61065,7 +61065,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": true,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -65862,7 +65862,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": false,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -65894,7 +65894,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": true,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -70546,7 +70546,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": false,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -70578,7 +70578,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": true,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -75272,7 +75272,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": false,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -75304,7 +75304,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": true,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -80040,7 +80040,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": false,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -80072,7 +80072,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": true,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -84787,7 +84787,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": false,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -84819,7 +84819,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": true,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -89513,7 +89513,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": false,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -89545,7 +89545,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": true,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -94239,7 +94239,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": false,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -94271,7 +94271,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": true,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -98965,7 +98965,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": false,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
@@ -98997,7 +98997,7 @@
           "expiration": 72000,
           "hard_timeout": 10800,
           "ignore_task_failure": true,
-          "io_timeout": 600,
+          "io_timeout": 1200,
           "upload_test_results": false
         }
       },
diff --git a/testing/buildbot/filters/unit_tests_cros_asan.filter b/testing/buildbot/filters/unit_tests_cros_asan.filter
index a0bb500d..494328b5f 100644
--- a/testing/buildbot/filters/unit_tests_cros_asan.filter
+++ b/testing/buildbot/filters/unit_tests_cros_asan.filter
@@ -1,2 +1,5 @@
 # TODO(crbug.com/756844): Fix memory leaks.
 -SafeBrowsingBlockingQuietPageTests.*
+
+# TODO(crbug.com/760309): Fix use after free.
+-FileManagerFileWatcherTest.WatchLocalFile
diff --git a/testing/libfuzzer/fuzzers/feature_policy_corpus/1 b/testing/libfuzzer/fuzzers/feature_policy_corpus/1
index 8c9fba4..fbbc34d 100644
--- a/testing/libfuzzer/fuzzers/feature_policy_corpus/1
+++ b/testing/libfuzzer/fuzzers/feature_policy_corpus/1
@@ -1 +1 @@
-Not a JSON literal
\ No newline at end of file
+badfeaturename
diff --git a/testing/libfuzzer/fuzzers/feature_policy_corpus/10 b/testing/libfuzzer/fuzzers/feature_policy_corpus/10
index 22e9803..e24e9938 100644
--- a/testing/libfuzzer/fuzzers/feature_policy_corpus/10
+++ b/testing/libfuzzer/fuzzers/feature_policy_corpus/10
@@ -1 +1 @@
-{"vibrate": ["self", "https://example.com/"]},{"vibrate": ["self", "https://example.net/"]}
\ No newline at end of file
+vibrate 'self' https://example.com/; vibrate 'self' https://example.net/
diff --git a/testing/libfuzzer/fuzzers/feature_policy_corpus/11 b/testing/libfuzzer/fuzzers/feature_policy_corpus/11
index 0f10777f..9dbfca6 100644
--- a/testing/libfuzzer/fuzzers/feature_policy_corpus/11
+++ b/testing/libfuzzer/fuzzers/feature_policy_corpus/11
@@ -1 +1 @@
-{"vibrate": ["self", "https://example.org/"]}
\ No newline at end of file
+vibrate 'self' https://example.org/
diff --git a/testing/libfuzzer/fuzzers/feature_policy_corpus/12 b/testing/libfuzzer/fuzzers/feature_policy_corpus/12
index b45d8ed..739ee648 100644
--- a/testing/libfuzzer/fuzzers/feature_policy_corpus/12
+++ b/testing/libfuzzer/fuzzers/feature_policy_corpus/12
@@ -1 +1 @@
-{"docwrite": ["self", "https://example.org/"]}
\ No newline at end of file
+docwrite 'self' https://example.org/
diff --git a/testing/libfuzzer/fuzzers/feature_policy_corpus/13 b/testing/libfuzzer/fuzzers/feature_policy_corpus/13
index 2172669..8b12493 100644
--- a/testing/libfuzzer/fuzzers/feature_policy_corpus/13
+++ b/testing/libfuzzer/fuzzers/feature_policy_corpus/13
@@ -1 +1 @@
-{"vibrate": ["self", "https://example.net/"]}, {"docwrite": ["self"]}
\ No newline at end of file
+vibrate 'self' https://example.net/; docwrite 'self'
diff --git a/testing/libfuzzer/fuzzers/feature_policy_corpus/14 b/testing/libfuzzer/fuzzers/feature_policy_corpus/14
index 86b0c2109..20d73ea 100644
--- a/testing/libfuzzer/fuzzers/feature_policy_corpus/14
+++ b/testing/libfuzzer/fuzzers/feature_policy_corpus/14
@@ -1 +1 @@
-{"vibrate": ["*"]}, {"docwrite": ["*"]}
\ No newline at end of file
+vibrate *; docwrite *
diff --git a/testing/libfuzzer/fuzzers/feature_policy_corpus/2 b/testing/libfuzzer/fuzzers/feature_policy_corpus/2
index 4c626d2..1d7a2af8 100644
--- a/testing/libfuzzer/fuzzers/feature_policy_corpus/2
+++ b/testing/libfuzzer/fuzzers/feature_policy_corpus/2
@@ -1 +1 @@
-"Not a JSON array"
\ No newline at end of file
+badfeaturename 'self'
diff --git a/testing/libfuzzer/fuzzers/feature_policy_corpus/3 b/testing/libfuzzer/fuzzers/feature_policy_corpus/3
index 6525f25..f06841c 100644
--- a/testing/libfuzzer/fuzzers/feature_policy_corpus/3
+++ b/testing/libfuzzer/fuzzers/feature_policy_corpus/3
@@ -1 +1 @@
-{"Also": "Not a JSON array"}
\ No newline at end of file
+vibrate data://badorigin
diff --git a/testing/libfuzzer/fuzzers/feature_policy_corpus/5 b/testing/libfuzzer/fuzzers/feature_policy_corpus/5
index 9670cc52..4f477a9 100644
--- a/testing/libfuzzer/fuzzers/feature_policy_corpus/5
+++ b/testing/libfuzzer/fuzzers/feature_policy_corpus/5
@@ -1 +1 @@
-[{"vibrate": ["self"]}]
\ No newline at end of file
+vibrate 'self'
diff --git a/testing/libfuzzer/fuzzers/feature_policy_corpus/6 b/testing/libfuzzer/fuzzers/feature_policy_corpus/6
index 84dd0c4..3f4c461 100644
--- a/testing/libfuzzer/fuzzers/feature_policy_corpus/6
+++ b/testing/libfuzzer/fuzzers/feature_policy_corpus/6
@@ -1 +1 @@
-{"vibrate": ["https://example.com/"]}
\ No newline at end of file
+vibrate https://example.com/
diff --git a/testing/libfuzzer/fuzzers/feature_policy_corpus/7 b/testing/libfuzzer/fuzzers/feature_policy_corpus/7
index cea37f8..e02eab5 100644
--- a/testing/libfuzzer/fuzzers/feature_policy_corpus/7
+++ b/testing/libfuzzer/fuzzers/feature_policy_corpus/7
@@ -1 +1 @@
-{"docwrite": []}
\ No newline at end of file
+docwrite 'none'
diff --git a/testing/libfuzzer/fuzzers/feature_policy_corpus/8 b/testing/libfuzzer/fuzzers/feature_policy_corpus/8
index ae0ba2c2..920f3a8 100644
--- a/testing/libfuzzer/fuzzers/feature_policy_corpus/8
+++ b/testing/libfuzzer/fuzzers/feature_policy_corpus/8
@@ -1 +1 @@
-{"docwrite": ["self"]}
\ No newline at end of file
+docwrite 'self'
diff --git a/testing/libfuzzer/fuzzers/feature_policy_corpus/9 b/testing/libfuzzer/fuzzers/feature_policy_corpus/9
index d8f6e2c..33696f7c 100644
--- a/testing/libfuzzer/fuzzers/feature_policy_corpus/9
+++ b/testing/libfuzzer/fuzzers/feature_policy_corpus/9
@@ -1 +1 @@
-{"vibrate": ["*"]}
\ No newline at end of file
+vibrate *
diff --git a/testing/scripts/content_shell_crash_test.py b/testing/scripts/content_shell_crash_test.py
index ad6412bb..a590cbd3 100755
--- a/testing/scripts/content_shell_crash_test.py
+++ b/testing/scripts/content_shell_crash_test.py
@@ -30,7 +30,7 @@
       required=True)
   parser.add_argument(
       '--isolated-script-test-chartjson-output', type=str,
-      required=True)
+      required=False)
   parser.add_argument(
       '--isolated-script-test-perf-output', type=str,
       required=False)
diff --git a/testing/scripts/run_gtest_perf_test.py b/testing/scripts/run_gtest_perf_test.py
index e89c8a4..3719cb7 100755
--- a/testing/scripts/run_gtest_perf_test.py
+++ b/testing/scripts/run_gtest_perf_test.py
@@ -63,7 +63,7 @@
       required=True)
   parser.add_argument(
       '--isolated-script-test-chartjson-output', type=str,
-      required=True)
+      required=False)
   parser.add_argument(
       '--isolated-script-test-perf-output', type=str,
       required=False)
@@ -110,8 +110,14 @@
         results_processor = (
             generate_legacy_perf_dashboard_json.LegacyResultsProcessor())
         charts = results_processor.GenerateJsonResults(tempfile_path)
+        # TODO(eakuefner): Make isolated_script_test_perf_output mandatory
+        # after flipping flag in swarming.
+        if args.isolated_script_test_perf_output:
+          filename = args.isolated_script_test_perf_output
+        else:
+          filename = args.isolated_script_test_chartjson_output
         # Write the returned encoded json to a the charts output file
-        with open(args.isolated_script_test_chartjson_output, 'w') as f:
+        with open(filename, 'w') as f:
           f.write(charts)
     except Exception:
       traceback.print_exc()
diff --git a/testing/scripts/run_telemetry_benchmark_as_googletest.py b/testing/scripts/run_telemetry_benchmark_as_googletest.py
index 2a72705fb..568afbd 100755
--- a/testing/scripts/run_telemetry_benchmark_as_googletest.py
+++ b/testing/scripts/run_telemetry_benchmark_as_googletest.py
@@ -105,10 +105,17 @@
     if rc == 0:
       rc = 1  # Signal an abnormal exit.
 
-  if chartjson_results_present and args.isolated_script_test_chartjson_output:
-    chartjson_output_file = \
-      open(args.isolated_script_test_chartjson_output, 'w')
-    json.dump(chartresults, chartjson_output_file)
+  if chartjson_results_present:
+    if args.isolated_script_test_perf_output:
+      filename = args.isolated_script_test_perf_output
+    elif args.isolated_script_test_chartjson_output:
+      filename = args.isolated_script_test_chartjson_output
+    else:
+      filename = None
+
+    if filename is not None:
+      with open(filename, 'w') as chartjson_output_file:
+        json.dump(chartresults, chartjson_output_file)
 
   json.dump(json_test_results, args.isolated_script_test_output)
   return rc
diff --git a/testing/scripts/sizes.py b/testing/scripts/sizes.py
index 2700859..3713fae 100755
--- a/testing/scripts/sizes.py
+++ b/testing/scripts/sizes.py
@@ -3,6 +3,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import argparse
 import json
 import os
 import sys
@@ -11,15 +12,43 @@
 import common
 
 
-def main_run(args):
+PERF_DASHBOARD_URL = 'https://chromeperf.appspot.com'
+
+
+def create_argparser():
+  parser = argparse.ArgumentParser()
+  parser.add_argument('--platform')
+  parser.add_argument('--perf-id')
+  parser.add_argument('--results-url', default=PERF_DASHBOARD_URL)
+  return parser
+
+
+def main_run(script_args):
+  parser = create_argparser()
+  parser.add_argument('prefix')
+  args = parser.parse_args(script_args.args)
+
   with common.temporary_file() as tempfile_path:
-    rc = common.run_runtest(args, [
-        '--test-type', 'sizes',
-        '--run-python-script',
+    runtest_args = [
+      '--test-type', 'sizes',
+      '--run-python-script',
+    ]
+    if args.perf_id:
+      runtest_args.extend([
+          '--perf-id', args.perf_id,
+          '--results-url=%s' % args.results_url,
+          '--perf-dashboard-id=sizes',
+          '--annotate=graphing',
+      ])
+    sizes_cmd = [
         os.path.join(
             common.SRC_DIR, 'infra', 'scripts', 'legacy', 'scripts', 'slave',
             'chromium', 'sizes.py'),
-        '--json', tempfile_path])
+        '--json', tempfile_path
+    ]
+    if args.platform:
+      sizes_cmd.extend(['--platform', args.platform])
+    rc = common.run_runtest(script_args, runtest_args + sizes_cmd)
     with open(tempfile_path) as f:
       results = json.load(f)
 
@@ -27,13 +56,11 @@
                          'perf_expectations.json')) as f:
     perf_expectations = json.load(f)
 
-  prefix = args.args[0]
-
   valid = (rc == 0)
   failures = []
 
   for name, result in results.iteritems():
-    fqtn = '%s/%s/%s' % (prefix, name, result['identifier'])
+    fqtn = '%s/%s/%s' % (args.prefix, name, result['identifier'])
     if fqtn not in perf_expectations:
       continue
 
@@ -56,7 +83,7 @@
   json.dump({
       'valid': valid,
       'failures': failures,
-  }, args.output)
+  }, script_args.output)
 
   # sizes.py itself doesn't fail on regressions.
   if failures and rc == 0:
@@ -65,8 +92,17 @@
   return rc
 
 
-def main_compile_targets(args):
-  json.dump(['chrome'], args.output)
+def main_compile_targets(script_args):
+  parser = create_argparser()
+  args = parser.parse_args(script_args.args)
+
+  _COMPILE_TARGETS = {
+    'android-cronet': ['cronet'],
+    'android-webview': ['libwebviewchromium'],
+  }
+
+  json.dump(_COMPILE_TARGETS.get(args.platform, ['chrome']),
+            script_args.output)
 
 
 if __name__ == '__main__':
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 6582acc..8682f5a 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -975,6 +975,24 @@
             ]
         }
     ],
+    "EnableNewMediaRouterRouteController": [
+        {
+            "platforms": [
+                "chromeos",
+                "linux",
+                "mac",
+                "win"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "MediaRouterUIRouteController"
+                    ]
+                }
+            ]
+        }
+    ],
     "ExpectCTReporting": [
         {
             "platforms": [
diff --git a/third_party/WebKit/LayoutTests/ASANExpectations b/third_party/WebKit/LayoutTests/ASANExpectations
index 7e5ed5d0..9ce19341 100644
--- a/third_party/WebKit/LayoutTests/ASANExpectations
+++ b/third_party/WebKit/LayoutTests/ASANExpectations
@@ -48,8 +48,10 @@
 crbug.com/438499 [ Linux ] fast/workers/worker-multi-startup.html [ Timeout ]
 crbug.com/438499 [ Linux ] http/tests/websocket/workers/worker-simple.html [ Timeout ]
 crbug.com/438499 [ Linux ] http/tests/workers/text-encoding.html [ Timeout ]
-crbug.com/438499 [ Linux ] inspector/profiler/heap-snapshot-loader.html [ Timeout ]
-crbug.com/438499 [ Linux ] inspector/profiler/heap-snapshot-containment-show-all.html [ Timeout ]
+crbug.com/438499 [ Linux ] http/tests/devtools/profiler/heap-snapshot-loader.html [ Timeout ]
+crbug.com/667560 [ Linux ] virtual/mojo-loading/http/tests/devtools/profiler/heap-snapshot-loader.html [ Timeout ]
+crbug.com/438499 [ Linux ] http/tests/devtools/profiler/heap-snapshot-containment-show-all.html [ Timeout ]
+crbug.com/667560 [ Linux ] virtual/mojo-loading/http/tests/devtools/profiler/heap-snapshot-containment-show-all.html [ Timeout ]
 crbug.com/438499 [ Linux ] virtual/threaded/animations/unanimated-style.html [ Timeout ]
 
 # Flakily timeout on Linux ASAN bots.
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index 7e229ad2..2134659d 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -12750,7 +12750,6 @@
 crbug.com/591099 http/tests/xmlhttprequest/access-control-preflight-credential-async.html [ Failure ]
 crbug.com/591099 http/tests/xmlhttprequest/access-control-preflight-data-saver.html [ Failure Timeout ]
 crbug.com/591099 http/tests/xmlhttprequest/access-control-preflight-headers-async.html [ Failure ]
-crbug.com/591099 http/tests/xmlhttprequest/access-control-preflight-request-header-lowercase.html [ Failure Timeout ]
 crbug.com/591099 http/tests/xmlhttprequest/access-control-preflight-request-header-sorted.html [ Failure ]
 crbug.com/591099 http/tests/xmlhttprequest/access-control-preflight-request-headers-origin.html [ Failure ]
 crbug.com/591099 http/tests/xmlhttprequest/access-control-preflight-request-invalid-status-301.html [ Failure ]
@@ -13726,44 +13725,82 @@
 crbug.com/591099 inspector/network/network-request-query-string.html [ Failure ]
 crbug.com/591099 inspector/network/network-toggle-type-filter.html [ Crash Failure ]
 crbug.com/591099 inspector/network/network-update-calculator-for-all-requests.html [ Failure ]
-crbug.com/591099 inspector/profiler/agents-disabled-check.html [ Crash Failure ]
-crbug.com/591099 inspector/profiler/cpu-profiler-agent-crash-on-start.html [ Crash Failure ]
-crbug.com/591099 inspector/profiler/cpu-profiler-bottom-up-large-tree-search.html [ Crash Failure ]
-crbug.com/591099 inspector/profiler/cpu-profiler-bottom-up-times.html [ Crash Failure ]
-crbug.com/591099 inspector/profiler/cpu-profiler-calculate-time.html [ Crash Failure ]
-crbug.com/591099 inspector/profiler/cpu-profiler-flame-chart-overview.html [ Crash Failure ]
-crbug.com/591099 inspector/profiler/cpu-profiler-native-nodes-filter.html [ Crash Failure ]
-crbug.com/591099 inspector/profiler/cpu-profiler-profile-removal.html [ Crash Failure ]
-crbug.com/591099 inspector/profiler/cpu-profiler-profiling.html [ Crash Failure ]
-crbug.com/591099 inspector/profiler/cpu-profiler-save-load.html [ Crash Failure ]
-crbug.com/591099 inspector/profiler/cpu-profiler-stopped-removed-race.html [ Crash Failure ]
-crbug.com/591099 inspector/profiler/heap-profiler-profiling.html [ Crash Failure ]
-crbug.com/591099 inspector/profiler/heap-snapshot-comparison-dom-groups-change.html [ Crash Failure ]
-crbug.com/591099 inspector/profiler/heap-snapshot-comparison-expansion-preserved-when-sorting.html [ Crash Failure ]
-crbug.com/591099 inspector/profiler/heap-snapshot-comparison-show-all.html [ Crash Failure ]
-crbug.com/591099 inspector/profiler/heap-snapshot-comparison-show-next.html [ Crash Failure ]
-crbug.com/591099 inspector/profiler/heap-snapshot-comparison-shown-node-count-preserved-when-sorting.html [ Crash Failure ]
-crbug.com/591099 inspector/profiler/heap-snapshot-comparison-sorting.html [ Crash Failure ]
-crbug.com/591099 inspector/profiler/heap-snapshot-containment-expansion-preserved-when-sorting.html [ Crash Failure ]
-crbug.com/591099 inspector/profiler/heap-snapshot-containment-show-all.html [ Crash Failure ]
-crbug.com/591099 inspector/profiler/heap-snapshot-containment-show-next.html [ Crash Failure ]
-crbug.com/591099 inspector/profiler/heap-snapshot-containment-shown-node-count-preserved-when-sorting.html [ Crash Failure ]
-crbug.com/591099 inspector/profiler/heap-snapshot-containment-sorting.html [ Crash Failure ]
-crbug.com/591099 inspector/profiler/heap-snapshot-inspect-dom-wrapper.html [ Crash Failure ]
-crbug.com/591099 inspector/profiler/heap-snapshot-loader.html [ Crash Failure ]
-crbug.com/591099 inspector/profiler/heap-snapshot-statistics.html [ Crash Failure ]
-crbug.com/591099 inspector/profiler/heap-snapshot-summary-expand-collapse.html [ Failure ]
-crbug.com/591099 inspector/profiler/heap-snapshot-summary-expansion-preserved-when-sorting.html [ Crash Failure ]
-crbug.com/591099 inspector/profiler/heap-snapshot-summary-search-by-id.html [ Crash Timeout ]
-crbug.com/591099 inspector/profiler/heap-snapshot-summary-search.html [ Crash Failure ]
-crbug.com/591099 inspector/profiler/heap-snapshot-summary-show-all.html [ Crash Failure ]
-crbug.com/591099 inspector/profiler/heap-snapshot-summary-show-next.html [ Crash Failure ]
-crbug.com/591099 inspector/profiler/heap-snapshot-summary-show-ranges.html [ Crash Failure ]
-crbug.com/591099 inspector/profiler/heap-snapshot-summary-shown-node-count-preserved-when-sorting.html [ Crash Failure ]
-crbug.com/591099 inspector/profiler/heap-snapshot-summary-sorting-fields.html [ Crash Failure ]
-crbug.com/591099 inspector/profiler/heap-snapshot-summary-sorting-instances.html [ Crash Failure ]
-crbug.com/591099 inspector/profiler/heap-snapshot-summary-sorting.html [ Crash Failure ]
-crbug.com/591099 inspector/profiler/heap-snapshot.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/profiler/agents-disabled-check.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/agents-disabled-check.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/profiler/cpu-profiler-agent-crash-on-start.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/cpu-profiler-agent-crash-on-start.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/profiler/cpu-profiler-bottom-up-large-tree-search.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/cpu-profiler-bottom-up-large-tree-search.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/profiler/cpu-profiler-bottom-up-times.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/cpu-profiler-bottom-up-times.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/profiler/cpu-profiler-calculate-time.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/cpu-profiler-calculate-time.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/profiler/cpu-profiler-flame-chart-overview.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/cpu-profiler-flame-chart-overview.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/profiler/cpu-profiler-native-nodes-filter.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/cpu-profiler-native-nodes-filter.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/profiler/cpu-profiler-profile-removal.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/cpu-profiler-profile-removal.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/profiler/cpu-profiler-profiling.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/cpu-profiler-profiling.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/profiler/cpu-profiler-save-load.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/cpu-profiler-save-load.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/profiler/cpu-profiler-stopped-removed-race.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/cpu-profiler-stopped-removed-race.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/profiler/heap-profiler-profiling.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/heap-profiler-profiling.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/profiler/heap-snapshot-comparison-dom-groups-change.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/heap-snapshot-comparison-dom-groups-change.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/profiler/heap-snapshot-comparison-expansion-preserved-when-sorting.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/heap-snapshot-comparison-expansion-preserved-when-sorting.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/profiler/heap-snapshot-comparison-show-all.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/heap-snapshot-comparison-show-all.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/profiler/heap-snapshot-comparison-show-next.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/heap-snapshot-comparison-show-next.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/profiler/heap-snapshot-comparison-shown-node-count-preserved-when-sorting.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/heap-snapshot-comparison-shown-node-count-preserved-when-sorting.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/profiler/heap-snapshot-comparison-sorting.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/heap-snapshot-comparison-sorting.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/profiler/heap-snapshot-containment-expansion-preserved-when-sorting.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/heap-snapshot-containment-expansion-preserved-when-sorting.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/profiler/heap-snapshot-containment-show-all.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/heap-snapshot-containment-show-all.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/profiler/heap-snapshot-containment-show-next.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/heap-snapshot-containment-show-next.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/profiler/heap-snapshot-containment-shown-node-count-preserved-when-sorting.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/heap-snapshot-containment-shown-node-count-preserved-when-sorting.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/profiler/heap-snapshot-containment-sorting.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/heap-snapshot-containment-sorting.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/profiler/heap-snapshot-inspect-dom-wrapper.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/heap-snapshot-inspect-dom-wrapper.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/profiler/heap-snapshot-loader.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/heap-snapshot-loader.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/profiler/heap-snapshot-statistics.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/heap-snapshot-statistics.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/profiler/heap-snapshot-summary-expand-collapse.html [ Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/heap-snapshot-summary-expand-collapse.html [ Failure ]
+crbug.com/591099 http/tests/devtools/profiler/heap-snapshot-summary-expansion-preserved-when-sorting.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/heap-snapshot-summary-expansion-preserved-when-sorting.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/profiler/heap-snapshot-summary-search-by-id.html [ Crash Timeout ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/heap-snapshot-summary-search-by-id.html [ Crash Timeout ]
+crbug.com/591099 http/tests/devtools/profiler/heap-snapshot-summary-search.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/heap-snapshot-summary-search.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/profiler/heap-snapshot-summary-show-all.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/heap-snapshot-summary-show-all.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/profiler/heap-snapshot-summary-show-next.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/heap-snapshot-summary-show-next.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/profiler/heap-snapshot-summary-show-ranges.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/heap-snapshot-summary-show-ranges.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/profiler/heap-snapshot-summary-shown-node-count-preserved-when-sorting.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/heap-snapshot-summary-shown-node-count-preserved-when-sorting.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/profiler/heap-snapshot-summary-sorting-fields.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/heap-snapshot-summary-sorting-fields.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/profiler/heap-snapshot-summary-sorting-instances.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/heap-snapshot-summary-sorting-instances.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/profiler/heap-snapshot-summary-sorting.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/heap-snapshot-summary-sorting.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/profiler/heap-snapshot.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/profiler/heap-snapshot.html [ Crash Failure ]
 crbug.com/591099 inspector/quick-open/command-menu.html [ Crash Failure ]
 crbug.com/591099 inspector/remote-object.html [ Failure ]
 crbug.com/591099 inspector/report-API-errors.html [ Failure ]
@@ -14236,67 +14273,128 @@
 crbug.com/591099 inspector/tracing-model-storage.html [ Failure ]
 crbug.com/591099 inspector/tracing-model.html [ Failure ]
 crbug.com/591099 inspector/tracing-session-id.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/anonymous-image-object.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/buffer-usage.html [ Failure ]
-crbug.com/591099 inspector/tracing/category-filter.html [ Failure ]
-crbug.com/591099 inspector/tracing/console-timeline.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/decode-resize.html [ Crash Failure Timeout ]
-crbug.com/591099 inspector/tracing/frame-model.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/hit-test.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/scroll-invalidations.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-js/compile-script.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-js/timeline-gc-event.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-js/timeline-microtasks.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-js/timeline-open-function-call.html [ Failure ]
-crbug.com/591099 inspector/tracing/timeline-js/timeline-runtime-stats.html [ Crash Failure Pass ]
-crbug.com/591099 inspector/tracing/timeline-js/timeline-script-id.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-js/timeline-script-tag-1.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-js/timeline-script-tag-2.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-layout/timeline-layout-reason.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-layout/timeline-layout-with-invalidations.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-layout/timeline-layout.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-misc/timeline-animation-frame.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-misc/timeline-bound-function.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-misc/timeline-event-causes.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-misc/timeline-event-details.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-misc/timeline-event-dispatch.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-misc/timeline-filtering.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-misc/timeline-flame-chart-automatically-size-window.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-misc/timeline-grouped-invalidations.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-misc/timeline-load-event.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-misc/timeline-mark-timeline.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-misc/timeline-model.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-misc/timeline-node-reference.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-misc/timeline-parse-html.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-misc/timeline-range-stats.html [ Failure ]
-crbug.com/591099 inspector/tracing/timeline-misc/timeline-record-reload.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-misc/timeline-search.html [ Failure ]
-crbug.com/591099 inspector/tracing/timeline-misc/timeline-tree-search.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-misc/timeline-trivial.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-misc/timeline-window-filter.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-network/timeline-network-resource-details.html [ Failure ]
-crbug.com/591099 inspector/tracing/timeline-network/timeline-network-resource.html [ Failure ]
-crbug.com/591099 inspector/tracing/timeline-paint/paint-profiler-update.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-paint/timeline-paint-image.html [ Failure ]
-crbug.com/591099 inspector/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-paint/timeline-paint-with-layout-invalidations.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-paint/timeline-paint.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-paint/update-layer-tree.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-style/parse-author-style-sheet.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-style/timeline-recalculate-styles.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-style/timeline-style-recalc-with-invalidations.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-time/timeline-time-stamp.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-time/timeline-time.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-time/timeline-timer-fired-from-eval-call-site.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-time/timeline-timer.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/timeline-time/timeline-usertiming.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/tracing-timeline-load.html [ Failure ]
-crbug.com/591099 inspector/tracing/worker-events.html [ Crash Failure ]
-crbug.com/591099 inspector/tracing/worker-js-frames.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/anonymous-image-object.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/anonymous-image-object.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/buffer-usage.html [ Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/buffer-usage.html [ Failure ]
+crbug.com/591099 http/tests/devtools/tracing/category-filter.html [ Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/category-filter.html [ Failure ]
+crbug.com/591099 http/tests/devtools/tracing/console-timeline.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/console-timeline.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/decode-resize.html [ Crash Failure Timeout ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/decode-resize.html [ Crash Failure Timeout ]
+crbug.com/591099 http/tests/devtools/tracing/frame-model.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/frame-model.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/hit-test.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/hit-test.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/scroll-invalidations.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/scroll-invalidations.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-js/compile-script.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-js/compile-script.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-js/timeline-gc-event.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-js/timeline-gc-event.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-js/timeline-microtasks.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-js/timeline-microtasks.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-js/timeline-open-function-call.html [ Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-js/timeline-open-function-call.html [ Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-js/timeline-runtime-stats.html [ Crash Failure Pass ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-js/timeline-runtime-stats.html [ Crash Failure Pass ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-js/timeline-script-id.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-js/timeline-script-id.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-js/timeline-script-tag-1.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-js/timeline-script-tag-1.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-js/timeline-script-tag-2.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-js/timeline-script-tag-2.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-layout/timeline-layout-reason.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-layout/timeline-layout-reason.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-layout/timeline-layout-with-invalidations.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-layout/timeline-layout-with-invalidations.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-layout/timeline-layout.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-layout/timeline-layout.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-misc/timeline-animation-frame.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-misc/timeline-animation-frame.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-misc/timeline-bound-function.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-misc/timeline-bound-function.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-misc/timeline-event-causes.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-misc/timeline-event-causes.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-misc/timeline-event-details.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-misc/timeline-event-details.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-misc/timeline-event-dispatch.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-misc/timeline-event-dispatch.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-misc/timeline-filtering.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-misc/timeline-filtering.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-misc/timeline-flame-chart-automatically-size-window.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-misc/timeline-flame-chart-automatically-size-window.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-misc/timeline-grouped-invalidations.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-misc/timeline-grouped-invalidations.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-misc/timeline-load-event.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-misc/timeline-load-event.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-misc/timeline-mark-timeline.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-misc/timeline-mark-timeline.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-misc/timeline-model.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-misc/timeline-model.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-misc/timeline-node-reference.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-misc/timeline-node-reference.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-misc/timeline-parse-html.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-misc/timeline-parse-html.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-misc/timeline-range-stats.html [ Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-misc/timeline-range-stats.html [ Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-misc/timeline-record-reload.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-misc/timeline-record-reload.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-misc/timeline-search.html [ Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-misc/timeline-search.html [ Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-misc/timeline-tree-search.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-misc/timeline-tree-search.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-misc/timeline-trivial.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-misc/timeline-trivial.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-misc/timeline-window-filter.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-misc/timeline-window-filter.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-network/timeline-network-resource-details.html [ Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-network/timeline-network-resource-details.html [ Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-network/timeline-network-resource.html [ Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-network/timeline-network-resource.html [ Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-paint/paint-profiler-update.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-paint/paint-profiler-update.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-paint/timeline-paint-image.html [ Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-paint/timeline-paint-image.html [ Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-paint/timeline-paint.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-paint/timeline-paint.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-paint/update-layer-tree.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-paint/update-layer-tree.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-style/parse-author-style-sheet.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-style/parse-author-style-sheet.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-style/timeline-recalculate-styles.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-style/timeline-recalculate-styles.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidations.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidations.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-time/timeline-time-stamp.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-time/timeline-time-stamp.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-time/timeline-time.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-time/timeline-time.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-time/timeline-timer-fired-from-eval-call-site.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-time/timeline-timer-fired-from-eval-call-site.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-time/timeline-timer.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-time/timeline-timer.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/timeline-time/timeline-usertiming.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-time/timeline-usertiming.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/tracing-timeline-load.html [ Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/tracing-timeline-load.html [ Failure ]
+crbug.com/591099 http/tests/devtools/tracing/worker-events.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/worker-events.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/worker-js-frames.html [ Crash Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/worker-js-frames.html [ Crash Failure ]
 crbug.com/591099 inspector/uisourcecode-revisions.html [ Failure ]
 crbug.com/591099 inspector/user-metrics.html [ Failure ]
 crbug.com/591099 inspector/version-controller.html [ Failure ]
@@ -18675,7 +18773,6 @@
 crbug.com/591099 virtual/mojo-loading/http/tests/xmlhttprequest/access-control-preflight-credential-async.html [ Failure ]
 crbug.com/591099 virtual/mojo-loading/http/tests/xmlhttprequest/access-control-preflight-data-saver.html [ Failure ]
 crbug.com/591099 virtual/mojo-loading/http/tests/xmlhttprequest/access-control-preflight-headers-async.html [ Failure ]
-crbug.com/591099 virtual/mojo-loading/http/tests/xmlhttprequest/access-control-preflight-request-header-lowercase.html [ Failure ]
 crbug.com/591099 virtual/mojo-loading/http/tests/xmlhttprequest/access-control-preflight-request-header-sorted.html [ Failure ]
 crbug.com/591099 virtual/mojo-loading/http/tests/xmlhttprequest/access-control-preflight-request-headers-origin.html [ Failure ]
 crbug.com/591099 virtual/mojo-loading/http/tests/xmlhttprequest/access-control-preflight-request-invalid-status-301.html [ Failure ]
@@ -19423,68 +19520,68 @@
 crbug.com/591099 virtual/threaded/fast/scroll-behavior/smooth-scroll/keyboard-scroll.html [ Failure ]
 crbug.com/591099 virtual/threaded/fast/scroll-behavior/smooth-scroll/main-thread-scrolling-reason-added.html [ Failure ]
 crbug.com/591099 virtual/threaded/fast/scroll-behavior/smooth-scroll/main-thread-scrolling-reason-correctness.html [ Failure Timeout ]
-crbug.com/591099 virtual/threaded/inspector/tracing/anonymous-image-object.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/buffer-usage.html [ Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/category-filter.html [ Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/console-timeline.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/decode-resize.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/frame-model.html [ Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/hit-test.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/idle-callback.html [ Crash Failure Timeout ]
-crbug.com/591099 virtual/threaded/inspector/tracing/scroll-invalidations.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-js/compile-script.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-js/timeline-gc-event.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-js/timeline-microtasks.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-js/timeline-open-function-call.html [ Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-js/timeline-runtime-stats.html [ Crash Failure Pass ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-js/timeline-script-id.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-js/timeline-script-tag-1.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-js/timeline-script-tag-2.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-layout/timeline-layout-reason.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-layout/timeline-layout-with-invalidations.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-layout/timeline-layout.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-misc/timeline-animation-frame.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-misc/timeline-bound-function.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-misc/timeline-event-causes.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-misc/timeline-event-details.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-misc/timeline-event-dispatch.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-misc/timeline-filtering.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-misc/timeline-flame-chart-automatically-size-window.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-misc/timeline-grouped-invalidations.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-misc/timeline-load-event.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-misc/timeline-mark-timeline.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-misc/timeline-model.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-misc/timeline-node-reference.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-misc/timeline-parse-html.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-misc/timeline-range-stats.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-misc/timeline-record-reload.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-misc/timeline-search.html [ Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-misc/timeline-tree-search.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-misc/timeline-trivial.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-misc/timeline-window-filter.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-network/timeline-network-resource-details.html [ Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-network/timeline-network-resource.html [ Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-paint/paint-profiler-update.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-paint/timeline-paint-image.html [ Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-paint/timeline-paint-with-layout-invalidations.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-paint/timeline-paint.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-paint/update-layer-tree.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-style/parse-author-style-sheet.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-style/timeline-recalculate-styles.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-style/timeline-style-recalc-with-invalidations.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-time/timeline-time-stamp.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-time/timeline-time.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-time/timeline-timer-fired-from-eval-call-site.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-time/timeline-timer.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/timeline-time/timeline-usertiming.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/tracing-timeline-load.html [ Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/worker-events.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/inspector/tracing/worker-js-frames.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/anonymous-image-object.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/buffer-usage.html [ Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/category-filter.html [ Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/console-timeline.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/decode-resize.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/frame-model.html [ Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/hit-test.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/idle-callback.html [ Crash Failure Timeout ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/scroll-invalidations.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-js/compile-script.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-js/timeline-gc-event.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-js/timeline-microtasks.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-js/timeline-open-function-call.html [ Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-js/timeline-runtime-stats.html [ Crash Failure Pass ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-js/timeline-script-id.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-js/timeline-script-tag-1.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-js/timeline-script-tag-2.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-layout/timeline-layout-reason.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-layout/timeline-layout-with-invalidations.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-layout/timeline-layout.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-animation-frame.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-bound-function.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-event-causes.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-event-details.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-event-dispatch.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-filtering.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-flame-chart-automatically-size-window.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-grouped-invalidations.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-load-event.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-mark-timeline.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-model.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-node-reference.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-parse-html.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-range-stats.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-record-reload.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-search.html [ Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-tree-search.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-trivial.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-window-filter.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-network/timeline-network-resource-details.html [ Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-network/timeline-network-resource.html [ Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-paint/paint-profiler-update.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-paint/timeline-paint-image.html [ Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-paint/timeline-paint.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-paint/update-layer-tree.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-style/parse-author-style-sheet.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-style/timeline-recalculate-styles.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidations.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-time/timeline-time-stamp.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-time/timeline-time.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-time/timeline-timer-fired-from-eval-call-site.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-time/timeline-timer.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-time/timeline-usertiming.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/tracing-timeline-load.html [ Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/worker-events.html [ Crash Failure ]
+crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/worker-js-frames.html [ Crash Failure ]
 crbug.com/591099 virtual/threaded/printing/absolute-position-headers-and-footers.html [ Failure ]
 crbug.com/591099 virtual/threaded/printing/absolute-positioned.html [ Failure ]
 crbug.com/591099 virtual/threaded/printing/allowed-page-breaks.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2 b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
index f4d30a76..cfdc29d 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
@@ -1664,7 +1664,7 @@
 crbug.com/686897 virtual/threaded/fast/compositorworker/basic-plumbing-main-to-worker.html [ Crash Failure Timeout ]
 
 # virtual/threaded variants of sub-directories and tests already skipped or marked as failing above.
-Bug(none) virtual/threaded/inspector/ [ Skip ]
+Bug(none) virtual/threaded/http/tests/devtools/ [ Skip ]
 Bug(none) virtual/threaded/fast/scroll-behavior/ [ Skip ]
 Bug(none) virtual/threaded/compositing/visibility/layer-visible-content.html [ Failure ]
 Bug(none) virtual/threaded/compositing/visibility/overlays.html [ Failure Crash ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/root-layer-scrolls b/third_party/WebKit/LayoutTests/FlagExpectations/root-layer-scrolls
index fc7b875..378dae47 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/root-layer-scrolls
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/root-layer-scrolls
@@ -457,14 +457,22 @@
 crbug.com/417782 inspector/layers/layers-3d-view-hit-testing.html [ Crash Pass ]
 crbug.com/417782 inspector/layers/layers-panel-mouse-events.html [ Crash Pass ]
 crbug.com/417782 inspector/layers/no-overlay-layers.html [ Crash Pass ]
-crbug.com/417782 inspector/tracing/scroll-invalidations.html [ Failure ]
-crbug.com/417782 inspector/tracing/timeline-paint/layer-tree.html [ Failure ]
-crbug.com/417782 inspector/tracing/timeline-paint/paint-profiler-update.html [ Timeout ]
-crbug.com/417782 inspector/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations.html [ Failure ]
-crbug.com/417782 inspector/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.html [ Failure ]
-crbug.com/417782 inspector/tracing/timeline-paint/timeline-paint-with-layout-invalidations.html [ Failure ]
-crbug.com/417782 inspector/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations.html [ Failure ]
-crbug.com/417782 inspector/tracing/timeline-paint/timeline-paint.html [ Failure ]
+crbug.com/417782 http/tests/devtools/tracing/scroll-invalidations.html [ Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/scroll-invalidations.html [ Failure ]
+crbug.com/417782 http/tests/devtools/tracing/timeline-paint/layer-tree.html [ Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-paint/layer-tree.html [ Failure ]
+crbug.com/417782 http/tests/devtools/tracing/timeline-paint/paint-profiler-update.html [ Timeout ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-paint/paint-profiler-update.html [ Timeout ]
+crbug.com/417782 http/tests/devtools/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations.html [ Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations.html [ Failure ]
+crbug.com/417782 http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.html [ Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.html [ Failure ]
+crbug.com/417782 http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations.html [ Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations.html [ Failure ]
+crbug.com/417782 http/tests/devtools/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations.html [ Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations.html [ Failure ]
+crbug.com/417782 http/tests/devtools/tracing/timeline-paint/timeline-paint.html [ Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-paint/timeline-paint.html [ Failure ]
 crbug.com/417782 intersection-observer/cross-origin-iframe.html [ Failure Pass ]
 crbug.com/417782 intersection-observer/iframe-no-root.html [ Failure Pass ]
 crbug.com/417782 intersection-observer/multiple-targets.html [ Failure Pass ]
@@ -1407,14 +1415,14 @@
 crbug.com/417782 virtual/threaded/fast/scroll-behavior/subframe-scrollLeft.html [ Failure ]
 crbug.com/417782 virtual/threaded/fast/scroll-behavior/subframe-scrollTo.html [ Failure ]
 crbug.com/417782 virtual/threaded/fast/scroll-behavior/subframe-scrollTop.html [ Failure ]
-crbug.com/417782 virtual/threaded/inspector/tracing/scroll-invalidations.html [ Failure ]
-crbug.com/417782 virtual/threaded/inspector/tracing/timeline-paint/paint-profiler-update.html [ Timeout ]
-crbug.com/417782 virtual/threaded/inspector/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations.html [ Failure ]
-crbug.com/417782 virtual/threaded/inspector/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.html [ Failure ]
-crbug.com/417782 virtual/threaded/inspector/tracing/timeline-paint/timeline-paint-with-layout-invalidations.html [ Failure ]
-crbug.com/417782 virtual/threaded/inspector/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations.html [ Failure ]
-crbug.com/417782 virtual/threaded/inspector/tracing/timeline-paint/timeline-paint.html [ Failure ]
-crbug.com/417782 [ Win ] virtual/threaded/inspector/tracing/timeline-paint/update-layer-tree.html [ Crash ]
+crbug.com/417782 virtual/threaded/http/tests/devtools/tracing/scroll-invalidations.html [ Failure ]
+crbug.com/417782 virtual/threaded/http/tests/devtools/tracing/timeline-paint/paint-profiler-update.html [ Timeout ]
+crbug.com/417782 virtual/threaded/http/tests/devtools/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations.html [ Failure ]
+crbug.com/417782 virtual/threaded/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.html [ Failure ]
+crbug.com/417782 virtual/threaded/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations.html [ Failure ]
+crbug.com/417782 virtual/threaded/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations.html [ Failure ]
+crbug.com/417782 virtual/threaded/http/tests/devtools/tracing/timeline-paint/timeline-paint.html [ Failure ]
+crbug.com/417782 [ Win ] virtual/threaded/http/tests/devtools/tracing/timeline-paint/update-layer-tree.html [ Crash ]
 crbug.com/417782 virtual/threaded/printing/absolute-position-headers-and-footers.html [ Failure Pass ]
 crbug.com/417782 virtual/threaded/printing/absolute-positioned.html [ Failure Pass ]
 crbug.com/417782 virtual/threaded/printing/block-width-relayout-shrink.html [ Failure Pass ]
diff --git a/third_party/WebKit/LayoutTests/NeverFixTests b/third_party/WebKit/LayoutTests/NeverFixTests
index 04df249..b21f818 100644
--- a/third_party/WebKit/LayoutTests/NeverFixTests
+++ b/third_party/WebKit/LayoutTests/NeverFixTests
@@ -139,6 +139,26 @@
 # We don't allow to access external hosts in layout tests.
 external/wpt/html/the-xhtml-syntax/parsing-xhtml-documents/xhtml-mathml-dtd-entity-support.htm [ WontFix ]
 
+# CSS3 attribute / attr references have not been implemented (except for content)
+crbug.com/246571 external/wpt/css/css-values-3/attr-color-invalid-cast.html [ WontFix ]
+crbug.com/246571 external/wpt/css/css-values-3/attr-color-valid.html [ WontFix ]
+crbug.com/246571 external/wpt/css/css-values-3/attr-length-invalid-cast.html [ WontFix ]
+crbug.com/246571 external/wpt/css/css-values-3/attr-length-valid.html [ WontFix ]
+crbug.com/246571 external/wpt/css/css-values-3/attr-length-valid-zero.html [ WontFix ]
+crbug.com/246571 external/wpt/css/css-values-3/attr-length-valid-zero-nofallback.html [ WontFix ]
+crbug.com/246571 external/wpt/css/css-values-3/attr-px-invalid-cast.html [ WontFix ]
+crbug.com/246571 external/wpt/css/css-values-3/attr-px-valid.html [ WontFix ]
+
+# Failing WPT using ch unit in vertical orientation
+crbug.com/759914 external/wpt/css/css-values-3/ch-unit-002.html [ WontFix ]
+
+# Failing CSS values WPT needs waitUntilDone
+crbug.com/759921 external/wpt/css/css-values-3/vh_not_refreshing_on_chrome.html [ WontFix ]
+
+# Media queries do not support calc() for internal CSS length values
+crbug.com/421909 external/wpt/css/css-values-3/calc-in-media-queries-001.html [ WontFix ]
+crbug.com/421909 external/wpt/css/css-values-3/calc-in-media-queries-002.html [ WontFix ]
+
 # CSS2 tests that rely on undefined behaviors (height of line-height: normal).
 external/wpt/css/CSS2/linebox/inline-formatting-context-002.xht [ WontFix ]
 [ Linux Win ] external/wpt/css/CSS2/linebox/inline-formatting-context-003.xht [ WontFix ]
@@ -272,8 +292,6 @@
 # WPT subdirectories without owners.
 external/wpt/accelerometer [ WontFix ]
 external/wpt/assumptions [ WontFix ]
-external/wpt/css-values [ WontFix ]
-external/wpt/css/css-values-3 [ WontFix ]
 external/wpt/gyroscope [ WontFix ]
 external/wpt/magnetometer [ WontFix ]
 external/wpt/upgrade-insecure-requests [ WontFix ]
diff --git a/third_party/WebKit/LayoutTests/SlowTests b/third_party/WebKit/LayoutTests/SlowTests
index c31ad498..9fe9156 100644
--- a/third_party/WebKit/LayoutTests/SlowTests
+++ b/third_party/WebKit/LayoutTests/SlowTests
@@ -133,9 +133,9 @@
 crbug.com/450493 virtual/mojo-loading/http/tests/inspector/sources/ [ Slow ]
 crbug.com/450493 http/tests/inspector/stacktraces/ [ Slow ]
 crbug.com/450493 virtual/mojo-loading/http/tests/inspector/stacktraces/ [ Slow ]
-crbug.com/450493 inspector/profiler/ [ Slow ]
-crbug.com/420008 inspector/tracing/ [ Slow ]
-crbug.com/420008 virtual/threaded/inspector/tracing/ [ Slow ]
+crbug.com/450493 http/tests/devtools/profiler/ [ Slow ]
+crbug.com/420008 http/tests/devtools/tracing/ [ Slow ]
+crbug.com/420008 virtual/threaded/http/tests/devtools/tracing/ [ Slow ]
 crbug.com/246190 [ Release ] http/tests/inspector/indexeddb/ [ Slow ]
 crbug.com/246190 [ Release ] virtual/mojo-loading/http/tests/inspector/indexeddb/ [ Slow ]
 crbug.com/451577 [ Mac ] http/tests/inspector/extensions/extensions-sidebar.html [ Slow ]
@@ -269,15 +269,17 @@
 crbug.com/364250 [ Debug ] virtual/threaded/animations/interpolation/webkit-transform-interpolation.html [ Slow ]
 crbug.com/402379 [ Debug ] storage/indexeddb/cursor-continue-validity.html [ Slow ]
 crbug.com/402379 [ Debug ] storage/indexeddb/mozilla/indexes.html [ Slow ]
-crbug.com/504706 [ Linux ] inspector/profiler/heap-snapshot-containment-expansion-preserved-when-sorting.html [ Slow ]
-crbug.com/504706 [ Linux ] inspector/profiler/heap-snapshot-containment-sorting.html [ Slow ]
+crbug.com/504706 [ Linux ] http/tests/devtools/profiler/heap-snapshot-containment-expansion-preserved-when-sorting.html [ Slow ]
+crbug.com/667560 [ Linux ] virtual/mojo-loading/http/tests/devtools/profiler/heap-snapshot-containment-expansion-preserved-when-sorting.html [ Slow ]
+crbug.com/504706 [ Linux ] http/tests/devtools/profiler/heap-snapshot-containment-sorting.html [ Slow ]
+crbug.com/667560 [ Linux ] virtual/mojo-loading/http/tests/devtools/profiler/heap-snapshot-containment-sorting.html [ Slow ]
 crbug.com/440452 virtual/display_list_2d_canvas/fast/canvas/canvas-partial-invalidation-zoomed.html [ Slow ]
 crbug.com/480769 http/tests/inspector/service-workers/service-workers-redundant.html [ Slow ]
 crbug.com/480769 virtual/mojo-loading/http/tests/inspector/service-workers/service-workers-redundant.html [ Slow ]
 crbug.com/480769 http/tests/inspector/service-workers/service-worker-agents.html [ Slow ]
 crbug.com/480769 virtual/mojo-loading/http/tests/inspector/service-workers/service-worker-agents.html [ Slow ]
 crbug.com/504703 inspector-protocol/debugger/debugger-step-into-dedicated-worker.js [ Slow ]
-crbug.com/535478 [ Win ] virtual/threaded/inspector/tracing/decode-resize.html [ Slow ]
+crbug.com/535478 [ Win ] virtual/threaded/http/tests/devtools/tracing/decode-resize.html [ Slow ]
 crbug.com/548765 http/tests/inspector/console-fetch-logging.html [ Slow ]
 crbug.com/548765 virtual/mojo-loading/http/tests/inspector/console-fetch-logging.html [ Slow ]
 
@@ -497,17 +499,3 @@
 
 # This test continues to fail as timeout on Win7(dbg)
 crbug.com/757292 [ Win Debug ] external/wpt/encoding/legacy-mb-korean/euc-kr/euckr-encode-form-errors-han.html [ Slow ]
-
-# These tests create and destroys too many workers, and on debug build, V8 snapshot serializer takes long time to make an index book for external reference
-crbug.com/v8/6448 [ Debug ] external/wpt/service-workers/service-worker/link-element-register-mime-types.https.html [ Slow ]
-crbug.com/v8/6448 [ Debug ] external/wpt/service-workers/service-worker/registration-updateviacache.https.html [ Slow ]
-crbug.com/v8/6448 [ Debug ] external/wpt/service-workers/service-worker/registration-mime-types.https.html [ Slow ]
-crbug.com/v8/6448 [ Debug ] fast/workers/worker-exception-during-navigation.html [ Slow ]
-crbug.com/v8/6448 [ Debug ] virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-mime-types.https.html [ Slow ]
-crbug.com/v8/6448 [ Debug ] virtual/mojo-blobs/external/wpt/service-workers/service-worker/registration-updateviacache.https.html [ Slow ]
-crbug.com/v8/6448 [ Debug ] virtual/mojo-blobs/external/wpt/service-workers/service-worker/registration-mime-types.https.html [ Slow ]
-crbug.com/v8/6448 [ Debug ] virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/foreign-fetch-cors.https.html [ Slow ]
-crbug.com/v8/6448 [ Debug ] virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-mime-types.https.html [ Slow ]
-crbug.com/v8/6448 [ Debug ] virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/registration-updateviacache.https.html [ Slow ]
-crbug.com/v8/6448 [ Debug ] virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/registration-mime-types.https.html [ Slow ]
-crbug.com/v8/6448 [ Debug ] virtual/service-worker-script-streaming/http/tests/serviceworker/chromium/register-different-script-many-times.html [ Slow ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 0b2efd2..06f54bc8 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -536,7 +536,7 @@
 crbug.com/635619 virtual/layout_ng/fast/block/float/formatting-context-changes.html [ Failure Crash ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/independent-align-positioning.html [ Failure ]
 crbug.com/635619 [ Mac ] virtual/layout_ng/fast/block/float/intruding-painted-twice.html [ Failure ]
-crbug.com/635619 virtual/layout_ng/fast/block/float/line-break-after-white-space-crash.html [ Crash ]
+crbug.com/635619 virtual/layout_ng/fast/block/float/line-break-after-white-space-crash.html [ Crash Timeout ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/logical-bottom-exceeds-layoutunit-max.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/marquee-shrink-to-avoid-floats.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/negative-margin-on-element-avoiding-floats-with-margin-on-parent.html [ Failure ]
@@ -716,9 +716,11 @@
 crbug.com/569139 fast/js/string-replace-2.html [ Failure ]
 crbug.com/569139 fast/js/regexp-caching.html [ Failure ]
 crbug.com/597221 fast/dom/Window/window-postmessage-clone-deep-array.html [ Failure ]
-crbug.com/498539 [ Win ] inspector/tracing/decode-resize.html [ Failure Timeout ]
-crbug.com/498539 inspector/tracing/timeline-misc/timeline-bound-function.html [ Pass Failure ]
-crbug.com/498539 virtual/threaded/inspector/tracing/timeline-misc/timeline-bound-function.html [ Pass Failure ]
+crbug.com/498539 [ Win ] http/tests/devtools/tracing/decode-resize.html [ Failure Timeout ]
+crbug.com/667560 [ Win ] virtual/mojo-loading/http/tests/devtools/tracing/decode-resize.html [ Failure Timeout ]
+crbug.com/498539 http/tests/devtools/tracing/timeline-misc/timeline-bound-function.html [ Pass Failure ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-misc/timeline-bound-function.html [ Pass Failure ]
+crbug.com/498539 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-bound-function.html [ Pass Failure ]
 crbug.com/498539 [ Mac ] http/tests/devtools/sources/debugger/live-edit-no-reveal.html [ Crash Pass Timeout ]
 crbug.com/667560 [ Mac ] virtual/mojo-loading/http/tests/devtools/sources/debugger/live-edit-no-reveal.html [ Crash Pass Timeout ]
 crbug.com/498539 [ Win7 ] http/tests/devtools/sources/debugger-pause/debugger-eval-on-call-frame-inside-iframe.html [ Failure Pass ]
@@ -1159,8 +1161,10 @@
 # Part of a larger issue referenced in the bug. This specific issue will be fixed shortly.
 crbug.com/408159 accessibility/is-ignored-change-sends-notification.html [ Timeout ]
 
-crbug.com/504706 [ Linux ] inspector/profiler/heap-snapshot-containment-expansion-preserved-when-sorting.html [ Pass ]
-crbug.com/504706 [ Linux ] inspector/profiler/heap-snapshot-containment-sorting.html [ Pass ]
+crbug.com/504706 [ Linux ] http/tests/devtools/profiler/heap-snapshot-containment-expansion-preserved-when-sorting.html [ Pass ]
+crbug.com/667560 [ Linux ] virtual/mojo-loading/http/tests/devtools/profiler/heap-snapshot-containment-expansion-preserved-when-sorting.html [ Pass ]
+crbug.com/504706 [ Linux ] http/tests/devtools/profiler/heap-snapshot-containment-sorting.html [ Pass ]
+crbug.com/667560 [ Linux ] virtual/mojo-loading/http/tests/devtools/profiler/heap-snapshot-containment-sorting.html [ Pass ]
 
 # When drawing subpixel smoothed glyphs, CoreGraphics will fake bold the glyphs.
 # In this configuration, the pixel smoothed glyphs will be created from subpixel smoothed glyphs.
@@ -1577,7 +1581,7 @@
 
 crbug.com/620432 accessibility/aria-activedescendant.html [ Failure ]
 
-crbug.com/399507 virtual/threaded/inspector/tracing/timeline-paint/layer-tree.html [ Skip ]
+crbug.com/399507 virtual/threaded/http/tests/devtools/tracing/timeline-paint/layer-tree.html [ Skip ]
 
 crbug.com/635909 http/tests/devtools/sources/debugger-frameworks/frameworks-dom-xhr-event-breakpoints.html [ NeedsManualRebaseline Timeout ]
 crbug.com/667560 virtual/mojo-loading/http/tests/devtools/sources/debugger-frameworks/frameworks-dom-xhr-event-breakpoints.html [ NeedsManualRebaseline Timeout ]
@@ -1702,7 +1706,7 @@
 crbug.com/626703 external/wpt/web-nfc/idlharness.https.html [ Skip ]
 
 crbug.com/723741 virtual/threaded/animations/svg-attribute-composition/svg-startOffset-composition.html [ Failure Pass ]
-crbug.com/723741 virtual/threaded/inspector/tracing/idle-callback.html [ Failure Pass Timeout ]
+crbug.com/723741 virtual/threaded/http/tests/devtools/tracing/idle-callback.html [ Failure Pass Timeout ]
 crbug.com/723826 http/tests/security/w3c/cross-origin-objects.html [ Failure Pass ]
 crbug.com/723826 virtual/mojo-loading/http/tests/security/w3c/cross-origin-objects.html [ Failure Pass ]
 
@@ -1724,37 +1728,20 @@
 crbug.com/626703 virtual/mojo-loading/http/tests/inspector/persistence/persistence-tabbed-editor-opens-filesystem-uisourcecode.html [ Pass Failure ]
 crbug.com/626703 virtual/threaded/transitions/transition-end-event-multiple-03.html [ Pass Failure ]
 
-crbug.com/751952 editing/selection/modify_extend/extend_by_character.html [ Failure Pass ]
-crbug.com/761952 external/wpt/service-workers/service-worker/link-element-register-mime-types.https.html [ Failure Pass ]
-crbug.com/761952 external/wpt/service-workers/service-worker/link-element-register-scope.https.html [ Failure Pass ]
-crbug.com/761952 external/wpt/service-workers/service-worker/link-element-register-script.https.html [ Failure Pass ]
-crbug.com/761952 external/wpt/service-workers/service-worker/link-element-register-script-url.https.html [ Failure Pass ]
-crbug.com/761952 external/wpt/service-workers/service-worker/link-element-register-security-error.https.html [ Failure Pass ]
-crbug.com/761952 external/wpt/service-workers/service-worker/registration-mime-types.https.html [ Failure Pass ]
-crbug.com/761952 fast/dom/Range/getClientRects.html [ Failure Pass ]
-crbug.com/761952 http/tests/devtools/console/console-format.html [ Failure Pass ]
-crbug.com/761952 virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-mime-types.https.html [ Failure Pass ]
-crbug.com/761952 virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-scope.https.html [ Failure Pass ]
-crbug.com/761952 virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-script.https.html [ Failure Pass ]
-crbug.com/761952 virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-script-url.https.html [ Failure Pass ]
-crbug.com/761952 virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-security-error.https.html [ Failure Pass ]
-crbug.com/761952 virtual/mojo-blobs/external/wpt/service-workers/service-worker/registration-mime-types.https.html [ Failure Pass ]
-crbug.com/761952 virtual/origin-trials-runtimeflags-disabled/http/tests/origin_trials/webexposed/budget-api-origin-trial-interfaces.html [ Failure Pass ]
-crbug.com/761952 virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-mime-types.https.html [ Failure Pass ]
-crbug.com/761952 virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-scope.https.html [ Failure Pass ]
-crbug.com/761952 virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-script.https.html [ Failure Pass ]
-crbug.com/761952 virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-script-url.https.html [ Failure Pass ]
-crbug.com/761952 virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-security-error.https.html [ Failure Pass ]
-crbug.com/761952 external/wpt/beacon/headers/header-content-type.html [ Failure Pass Timeout ]
-crbug.com/761952 virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/registration-mime-types.https.html [ Failure Pass ]
-crbug.com/761952 fast/text/international/complex-text-rectangle.html [ Timeout Pass ]
-crbug.com/761952 external/wpt/2dcontext/imagebitmap/createImageBitmap-drawImage.html [ Failure Pass ]
-crbug.com/761952 external/wpt/audio-output/setSinkId.https.html [ Failure Pass ]
 crbug.com/761952 external/wpt/editing/run/forwarddelete.html [ Failure Pass Timeout ]
-crbug.com/761952 external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-data-url.html [ Failure Pass ]
-crbug.com/761952 external/wpt/payment-request/historical.https.html [ Failure Pass ]
-crbug.com/761952 external/wpt/uievents/auxclick/auxclick_event-manual.html [ Failure Pass ]
-crbug.com/761952 virtual/mojo-loading/http/tests/devtools/console/console-uncaught-promise.html [ Failure Pass ]
+crbug.com/761952 external/wpt/beacon/headers/header-content-type.html [ Failure Pass Timeout ]
+crbug.com/761952 fast/text/international/complex-text-rectangle.html [ Timeout Pass ]
+
+crbug.com/751952 editing/selection/modify_extend/extend_by_character.html [ Pass Failure ]
+crbug.com/751952 external/wpt/service-workers/service-worker/link-element-register-security-error.https.html [ Pass Failure ]
+crbug.com/751952 fast/dom/Range/getClientRects.html [ Pass Failure ]
+crbug.com/751952 http/tests/devtools/console/console-format.html [ Pass Failure ]
+crbug.com/751952 http/tests/inspector-unit/datagrid-editable-longtext.js [ Pass Failure ]
+crbug.com/751952 virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-security-error.https.html [ Pass Failure ]
+crbug.com/751952 virtual/mojo-loading/http/tests/devtools/console/console-uncaught-promise.html [ Pass Failure ]
+crbug.com/751952 virtual/mojo-loading/http/tests/inspector-unit/datagrid-editable-longtext.js [ Pass Failure ]
+crbug.com/751952 virtual/origin-trials-runtimeflags-disabled/http/tests/origin_trials/webexposed/budget-api-origin-trial-interfaces.html [ Pass Failure ]
+crbug.com/751952 virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-security-error.https.html [ Pass Failure ]
 
 # ====== New tests from wpt-importer added here ======
 crbug.com/626703 external/wpt/audio-output/setSinkId-manual.https.html [ Skip ]
@@ -2812,8 +2799,9 @@
 crbug.com/700374 [ Win ] http/tests/inspector/workers-on-navigation.html [ Failure Pass ]
 
 # Sheriff failures 2017-03-21
-crbug.com/703518 inspector/tracing/worker-js-frames.html [ Failure Pass ]
-crbug.com/703518 virtual/threaded/inspector/tracing/worker-js-frames.html [ Failure Pass ]
+crbug.com/703518 http/tests/devtools/tracing/worker-js-frames.html [ Failure Pass ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/worker-js-frames.html [ Failure Pass ]
+crbug.com/703518 virtual/threaded/http/tests/devtools/tracing/worker-js-frames.html [ Failure Pass ]
 crbug.com/674720 http/tests/loading/preload-img-test.html [ Pass Failure ]
 crbug.com/674720 virtual/mojo-loading/http/tests/loading/preload-img-test.html [ Pass Failure ]
 
@@ -3105,6 +3093,9 @@
 crbug.com/754657 http/tests/media/media-source/mediasource-duration.html [ Pass Failure ]
 crbug.com/626703 virtual/outofblink-cors/external/wpt/fetch/api/response/response-cancel-stream.html [ Pass Timeout ]
 
+# Sheriff failure 2017-08-29
+crbug.com/727252 [ Win7 ] external/wpt/media-source/mediasource-endofstream.html [ Pass Timeout ]
+
 # Ganesh dither changes
 crbug.com/753462 virtual/gpu/fast/canvas/canvas-text-alignment.html [ NeedsManualRebaseline ]
 crbug.com/753462 virtual/gpu/fast/canvas/fillrect_gradient.html [ NeedsManualRebaseline ]
@@ -3609,10 +3600,12 @@
 crbug.com/757955 [ Win7 Debug ] media/color-profile-video-seek-filter.html [ Pass Timeout ]
 crbug.com/757955 [ Win7 Debug ] virtual/threaded/animations/composited-animations-rotate-zero-degrees.html [ Pass Timeout ]
 crbug.com/757955 [ Win7 Debug ] external/wpt/encoding/legacy-mb-japanese/shift_jis/sjis-encode-form-errors-han.html [ Pass Timeout ]
-crbug.com/757955 [ Win7 Debug ] inspector/tracing/frame-model-instrumentation.html [ Pass Timeout ]
+crbug.com/757955 [ Win7 Debug ] http/tests/devtools/tracing/frame-model-instrumentation.html [ Pass Timeout ]
+crbug.com/667560 [ Win7 Debug ] virtual/mojo-loading/http/tests/devtools/tracing/frame-model-instrumentation.html [ Pass Timeout ]
 crbug.com/757955 [ Win7 Debug ] storage/indexeddb/mozilla/cursors.html [ Pass Timeout ]
 crbug.com/757955 [ Win7 Debug ] storage/indexeddb/objectstore-cursor.html [ Pass Timeout ]
-crbug.com/757955 [ Win7 Debug ] inspector/tracing/timeline-paint/layer-tree.html [ Pass Timeout ]
+crbug.com/757955 [ Win7 Debug ] http/tests/devtools/tracing/timeline-paint/layer-tree.html [ Pass Timeout ]
+crbug.com/667560 [ Win7 Debug ] virtual/mojo-loading/http/tests/devtools/tracing/timeline-paint/layer-tree.html [ Pass Timeout ]
 crbug.com/757955 [ Win7 Debug ] virtual/threaded/transitions/transition-end-event-transform.html [ Pass Failure ]
 
 # Tests flakely timing out on WebKit Linux Trusty dbg builder
@@ -3621,6 +3614,6 @@
 # This test has a fixed number of time which can depend on performance.
 crbug.com/v8/6448 [ Debug ] external/wpt/hr-time/window-worker-time-origin.html [ Pass Failure ]
 
-crbug.com/669329 inspector/tracing/timeline-js/timeline-runtime-stats.html [ Pass Failure Crash ]
-crbug.com/669329 virtual/threaded/inspector/tracing/timeline-js/timeline-runtime-stats.html [ Pass Failure Crash ]
-
+crbug.com/669329 http/tests/devtools/tracing/timeline-js/timeline-runtime-stats.html [ Pass Failure Crash ]
+crbug.com/669329 virtual/threaded/http/tests/devtools/tracing/timeline-js/timeline-runtime-stats.html [ Pass Failure Crash ]
+crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-js/timeline-runtime-stats.html [ Pass Failure Crash ]
diff --git a/third_party/WebKit/LayoutTests/VirtualTestSuites b/third_party/WebKit/LayoutTests/VirtualTestSuites
index 299c9ea..95bf3d9 100644
--- a/third_party/WebKit/LayoutTests/VirtualTestSuites
+++ b/third_party/WebKit/LayoutTests/VirtualTestSuites
@@ -233,7 +233,7 @@
   },
   {
     "prefix": "threaded",
-    "base": "inspector/tracing",
+    "base": "http/tests/devtools/tracing",
     "args": ["--enable-threaded-compositing"]
   },
   {
diff --git a/third_party/WebKit/LayoutTests/accessibility/aom-actions.html b/third_party/WebKit/LayoutTests/accessibility/aom-actions.html
index d22de17..743465c 100644
--- a/third_party/WebKit/LayoutTests/accessibility/aom-actions.html
+++ b/third_party/WebKit/LayoutTests/accessibility/aom-actions.html
@@ -2,6 +2,7 @@
 <script src="../resources/gc.js"></script>
 <script src="../resources/testharness.js"></script>
 <script src="../resources/testharnessreport.js"></script>
+<script src="../http/tests/resources/permissions-helper.js"></script>
 
 <!--
 
@@ -19,34 +20,53 @@
 <button id="target1">Target</button>
 
 <script>
-test(function(t) {
-  var target1 = document.getElementById("target1");
-  var axTarget1 = accessibilityController.accessibleElementById("target1");
+function enableAccessibilityEventsPermission() {
+  return new Promise(function(resolve, reject) {
+    PermissionsHelper.setPermission(
+        'accessibility-events', 'granted').then(function() {
+      // Make sure AXObjectCacheImpl gets the notification too, its
+      // listener may fire after this one.
+      window.setTimeout(function() {
+        resolve();
+      }, 0);
+    });
+  });
+}
 
-  var success = false;
-  target1.accessibleNode.onaccessibleclick = function() {
-    success = true;
-  };
-  axTarget1.press();
+async_test(function(t) {
+  enableAccessibilityEventsPermission().then(function() {
+    var target1 = document.getElementById("target1");
+    var axTarget1 = accessibilityController.accessibleElementById("target1");
 
-  assert_true(success);
+    var success = false;
+    target1.accessibleNode.onaccessibleclick = function() {
+      success = true;
+    };
+    axTarget1.press();
+
+    assert_true(success);
+    t.done();
+  });
 }, "AccessibleNode.onaccessibleclick");
 </script>
 
 <button id="target2">Target</button>
 
 <script>
-test(function(t) {
-  var target2 = document.getElementById("target2");
-  var axTarget2 = accessibilityController.accessibleElementById("target2");
+async_test(function(t) {
+  enableAccessibilityEventsPermission().then(function() {
+    var target2 = document.getElementById("target2");
+    var axTarget2 = accessibilityController.accessibleElementById("target2");
 
-  var success = false;
-  target2.accessibleNode.addEventListener("accessibleclick", function() {
-    success = true;
-  }, false);
-  axTarget2.press();
+    var success = false;
+    target2.accessibleNode.addEventListener("accessibleclick", function() {
+      success = true;
+    }, false);
+    axTarget2.press();
 
-  assert_true(success);
+    assert_true(success);
+    t.done();
+  });
 }, "AccessibleNode.addEventListener('accessibleclick')");
 </script>
 
@@ -54,41 +74,44 @@
 <button id="target3b">Target with preventDefault</button>
 
 <script>
-test(function(t) {
-  var target3a = document.getElementById("target3a");
-  var target3b = document.getElementById("target3b");
-  var axTarget3a = accessibilityController.accessibleElementById("target3a");
-  var axTarget3b = accessibilityController.accessibleElementById("target3b");
+async_test(function(t) {
+  enableAccessibilityEventsPermission().then(function() {
+    var target3a = document.getElementById("target3a");
+    var target3b = document.getElementById("target3b");
+    var axTarget3a = accessibilityController.accessibleElementById("target3a");
+    var axTarget3b = accessibilityController.accessibleElementById("target3b");
 
-  // Without preventDefault, the AOM event listener gets called
-  // first, and then the DOM event listener.
-  var calledAOMForTargetA = false;
-  target3a.accessibleNode.onaccessibleclick = function() {
-    calledAOMForTargetA = true;
-  };
-  var calledDOMForTargetA = false;
-  target3a.addEventListener("click", function() {
-    calledDOMForTargetA = true;
-  }, false);
-  axTarget3a.press();
+    // Without preventDefault, the AOM event listener gets called
+    // first, and then the DOM event listener.
+    var calledAOMForTargetA = false;
+    target3a.accessibleNode.onaccessibleclick = function() {
+      calledAOMForTargetA = true;
+    };
+    var calledDOMForTargetA = false;
+    target3a.addEventListener("click", function() {
+      calledDOMForTargetA = true;
+    }, false);
+    axTarget3a.press();
 
-  assert_true(calledAOMForTargetA, "called AOM for target A");
-  assert_true(calledDOMForTargetA, "called DOM for target A");
+    assert_true(calledAOMForTargetA, "called AOM for target A");
+    assert_true(calledDOMForTargetA, "called DOM for target A");
 
-  // With preventDefault, the AOM event listener gets called only.
-  var calledAOMForTargetB = false;
-  target3b.accessibleNode.onaccessibleclick = function(evt) {
-    calledAOMForTargetB = true;
-    evt.preventDefault();
-  };
-  var calledDOMForTargetB = false;
-  target3b.addEventListener("click", function() {
-    calledDOMForTargetB = true;
-  }, false);
-  axTarget3b.press();
+    // With preventDefault, the AOM event listener gets called only.
+    var calledAOMForTargetB = false;
+    target3b.accessibleNode.onaccessibleclick = function(evt) {
+      calledAOMForTargetB = true;
+      evt.preventDefault();
+    };
+    var calledDOMForTargetB = false;
+    target3b.addEventListener("click", function() {
+      calledDOMForTargetB = true;
+    }, false);
+    axTarget3b.press();
 
-  assert_true(calledAOMForTargetB, "called AOM for target B");
-  assert_false(calledDOMForTargetB, "called DOM for target B");
+    assert_true(calledAOMForTargetB, "called AOM for target B");
+    assert_false(calledDOMForTargetB, "called DOM for target B");
+    t.done();
+  });
 }, "AOM events preventDefault");
 </script>
 
@@ -97,17 +120,20 @@
 </p>
 
 <script>
-test(function(t) {
-  var p4 = document.getElementById("p4");
-  var axTarget4 = accessibilityController.accessibleElementById("target4");
+async_test(function(t) {
+  enableAccessibilityEventsPermission().then(function() {
+    var p4 = document.getElementById("p4");
+    var axTarget4 = accessibilityController.accessibleElementById("target4");
 
-  var success = false;
-  p4.accessibleNode.onaccessibleclick = function() {
-    success = true;
-  };
-  axTarget4.press();
+    var success = false;
+    p4.accessibleNode.onaccessibleclick = function() {
+      success = true;
+    };
+    axTarget4.press();
 
-  assert_true(success);
+    assert_true(success);
+    t.done();
+  });
 }, "AOM events bubble");
 </script>
 
@@ -120,61 +146,63 @@
 </section>
 
 <script>
-test(function(t) {
-  var section5 = document.getElementById("section5");
-  var ul5 = document.getElementById("ul5");
-  var li5 = document.getElementById("li5");
-  var target5 = document.getElementById("target5");
+async_test(function(t) {
+  enableAccessibilityEventsPermission().then(function() {
+    var section5 = document.getElementById("section5");
+    var ul5 = document.getElementById("ul5");
+    var li5 = document.getElementById("li5");
+    var target5 = document.getElementById("target5");
 
-  var axTarget5 = accessibilityController.accessibleElementById("target5");
+    var axTarget5 = accessibilityController.accessibleElementById("target5");
 
-  var seq = [];
+    var seq = [];
 
-  section5.accessibleNode.addEventListener("accessibleclick", function() {
-    seq.push("AOM capture SECTION");
-  }, true);
-  section5.accessibleNode.addEventListener("accessibleclick", function() {
-    seq.push("AOM bubble SECTION");
-  }, false);
-  section5.addEventListener("click", function() {
-    seq.push("DOM capture SECTION");
-  }, true);
-  section5.addEventListener("click", function() {
-    seq.push("DOM bubble SECTION");
-  }, false);
-  ul5.accessibleNode.addEventListener("accessibleclick", function() {
-    seq.push("AOM capture UL");
-  }, true);
-  ul5.accessibleNode.addEventListener("accessibleclick", function() {
-    seq.push("AOM bubble UL");
-  }, false);
-  li5.accessibleNode.addEventListener("accessibleclick", function() {
-    seq.push("AOM capture LI");
-  }, true);
-  li5.accessibleNode.addEventListener("accessibleclick", function() {
-    seq.push("AOM bubble LI");
-  }, false);
-  target5.accessibleNode.addEventListener("accessibleclick", function() {
-    seq.push("AOM main event listener BUTTON");
-  }, false);
-  target5.addEventListener("click", function() {
-    seq.push("DOM main event listener BUTTON");
-  }, false);
+    section5.accessibleNode.addEventListener("accessibleclick", function() {
+      seq.push("AOM capture SECTION");
+    }, true);
+    section5.accessibleNode.addEventListener("accessibleclick", function() {
+      seq.push("AOM bubble SECTION");
+    }, false);
+    section5.addEventListener("click", function() {
+      seq.push("DOM capture SECTION");
+    }, true);
+    section5.addEventListener("click", function() {
+      seq.push("DOM bubble SECTION");
+    }, false);
+    ul5.accessibleNode.addEventListener("accessibleclick", function() {
+      seq.push("AOM capture UL");
+    }, true);
+    ul5.accessibleNode.addEventListener("accessibleclick", function() {
+      seq.push("AOM bubble UL");
+    }, false);
+    li5.accessibleNode.addEventListener("accessibleclick", function() {
+      seq.push("AOM capture LI");
+    }, true);
+    li5.accessibleNode.addEventListener("accessibleclick", function() {
+      seq.push("AOM bubble LI");
+    }, false);
+    target5.accessibleNode.addEventListener("accessibleclick", function() {
+      seq.push("AOM main event listener BUTTON");
+    }, false);
+    target5.addEventListener("click", function() {
+      seq.push("DOM main event listener BUTTON");
+    }, false);
 
-  axTarget5.press();
+    axTarget5.press();
 
-  assert_equals(seq.join(", "),
-                "AOM capture SECTION, " +
-                "AOM capture UL, " +
-                "AOM capture LI, " +
-                "AOM main event listener BUTTON, " +
-                "AOM bubble LI, " +
-                "AOM bubble UL, " +
-                "AOM bubble SECTION, " +
-                "DOM capture SECTION, " +
-                "DOM main event listener BUTTON, " +
-                "DOM bubble SECTION");
-2
+    assert_equals(seq.join(", "),
+                  "AOM capture SECTION, " +
+                  "AOM capture UL, " +
+                  "AOM capture LI, " +
+                  "AOM main event listener BUTTON, " +
+                  "AOM bubble LI, " +
+                  "AOM bubble UL, " +
+                  "AOM bubble SECTION, " +
+                  "DOM capture SECTION, " +
+                  "DOM main event listener BUTTON, " +
+                  "DOM bubble SECTION");
+    t.done();
+  });
 }, "AOM event capturing and bubbling");
 </script>
 
@@ -187,25 +215,28 @@
 </section>
 
 <script>
-test(function(t) {
-  var ul6a = document.getElementById("ul6a");
-  var ul6b = document.getElementById("ul6b");
-  var li6b = document.getElementById("li6b");
+async_test(function(t) {
+  enableAccessibilityEventsPermission().then(function() {
+    var ul6a = document.getElementById("ul6a");
+    var ul6b = document.getElementById("ul6b");
+    var li6b = document.getElementById("li6b");
 
-  var axLI6B = accessibilityController.accessibleElementById("li6b");
+    var axLI6B = accessibilityController.accessibleElementById("li6b");
 
-  var ul6a_got_event = false;
-  var ul6b_got_event = false;
+    var ul6a_got_event = false;
+    var ul6b_got_event = false;
 
-  ul6a.accessibleNode.addEventListener("accessibleclick", function() {
-    ul6a_got_event = true;
-  }, false);
-  ul6b.accessibleNode.addEventListener("accessibleclick", function() {
-    ul6b_got_event = true;
-  }, false);
+    ul6a.accessibleNode.addEventListener("accessibleclick", function() {
+      ul6a_got_event = true;
+    }, false);
+    ul6b.accessibleNode.addEventListener("accessibleclick", function() {
+      ul6b_got_event = true;
+    }, false);
 
-  axLI6B.press();
-  assert_true(ul6a_got_event);
-  assert_false(ul6b_got_event);
+    axLI6B.press();
+    assert_true(ul6a_got_event);
+    assert_false(ul6b_got_event);
+    t.done();
+  });
 }, "AOM event bubbling respects aria-owns over DOM parent chain");
 </script>
diff --git a/third_party/WebKit/LayoutTests/compositing/contents-opaque/filter-expected.txt b/third_party/WebKit/LayoutTests/compositing/contents-opaque/filter-expected.txt
index ee83f27b..3a877dd 100644
--- a/third_party/WebKit/LayoutTests/compositing/contents-opaque/filter-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/contents-opaque/filter-expected.txt
@@ -9,7 +9,6 @@
     {
       "name": "LayoutBlockFlow DIV class='composited container-box'",
       "position": [-18, -18],
-      "transformOrigin": [78, 78],
       "bounds": [157, 157],
       "drawsContent": true
     },
diff --git a/third_party/WebKit/LayoutTests/compositing/contents-opaque/layer-transform-expected.txt b/third_party/WebKit/LayoutTests/compositing/contents-opaque/layer-transform-expected.txt
index 454907e..4ec408f 100644
--- a/third_party/WebKit/LayoutTests/compositing/contents-opaque/layer-transform-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/contents-opaque/layer-transform-expected.txt
@@ -13,12 +13,19 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#008000",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
       "transform": [
         [0.866025403784439, 0.5, 0, 0],
         [-0.5, 0.866025403784439, 0, 0],
         [0, 0, 1, 0],
         [0, 0, 0, 1]
-      ]
+      ],
+      "origin": [50, 50]
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/compositing/filters/sw-layer-overlaps-hw-shadow-expected.txt b/third_party/WebKit/LayoutTests/compositing/filters/sw-layer-overlaps-hw-shadow-expected.txt
index 50dc789..6ea9019 100644
--- a/third_party/WebKit/LayoutTests/compositing/filters/sw-layer-overlaps-hw-shadow-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/filters/sw-layer-overlaps-hw-shadow-expected.txt
@@ -7,8 +7,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='composited'",
diff --git a/third_party/WebKit/LayoutTests/compositing/filters/sw-nested-shadow-overlaps-hw-nested-shadow-expected.txt b/third_party/WebKit/LayoutTests/compositing/filters/sw-nested-shadow-overlaps-hw-nested-shadow-expected.txt
index e69bae1..11e9b69 100644
--- a/third_party/WebKit/LayoutTests/compositing/filters/sw-nested-shadow-overlaps-hw-nested-shadow-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/filters/sw-nested-shadow-overlaps-hw-nested-shadow-expected.txt
@@ -9,7 +9,6 @@
     {
       "name": "LayoutBlockFlow (positioned) DIV id='composited-parent'",
       "position": [230, 230],
-      "transformOrigin": [150, 150],
       "bounds": [200, 200],
       "drawsContent": true,
       "backgroundColor": "#000000"
diff --git a/third_party/WebKit/LayoutTests/compositing/fixed-body-background-positioned-expected.txt b/third_party/WebKit/LayoutTests/compositing/fixed-body-background-positioned-expected.txt
index 2e31822..e8f62f7b 100644
--- a/third_party/WebKit/LayoutTests/compositing/fixed-body-background-positioned-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/fixed-body-background-positioned-expected.txt
@@ -27,7 +27,6 @@
     },
     {
       "name": "LayoutView #document (background) Layer",
-      "transformOrigin": [0, 0],
       "bounds": [785, 600],
       "contentsOpaque": true,
       "drawsContent": true
diff --git a/third_party/WebKit/LayoutTests/compositing/fixed-position-changed-to-absolute-expected.txt b/third_party/WebKit/LayoutTests/compositing/fixed-position-changed-to-absolute-expected.txt
index 6d934d39..8249a94 100644
--- a/third_party/WebKit/LayoutTests/compositing/fixed-position-changed-to-absolute-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/fixed-position-changed-to-absolute-expected.txt
@@ -8,8 +8,7 @@
       "backgroundColor": "#402B3C"
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited'",
diff --git a/third_party/WebKit/LayoutTests/compositing/force-compositing-mode/overflow-iframe-enter-compositing-expected.txt b/third_party/WebKit/LayoutTests/compositing/force-compositing-mode/overflow-iframe-enter-compositing-expected.txt
index d0b3c31..e8029334 100644
--- a/third_party/WebKit/LayoutTests/compositing/force-compositing-mode/overflow-iframe-enter-compositing-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/force-compositing-mode/overflow-iframe-enter-compositing-expected.txt
@@ -15,38 +15,42 @@
     },
     {
       "name": "Frame Overflow Controls Host Layer",
-      "position": [2, 2],
+      "position": [10, 10],
       "bounds": [150, 150]
     },
     {
       "name": "Frame Clipping Layer",
+      "position": [10, 10],
       "bounds": [135, 135]
     },
     {
-      "name": "Frame Scrolling Layer"
+      "name": "Frame Scrolling Layer",
+      "position": [10, 10]
     },
     {
       "name": "Content Root Layer",
+      "position": [10, 10],
       "bounds": [508, 516]
     },
     {
       "name": "LayoutView #document",
+      "position": [10, 10],
       "bounds": [508, 516],
       "drawsContent": true
     },
     {
       "name": "Frame Horizontal Scrollbar Layer",
-      "position": [0, 135],
+      "position": [10, 145],
       "bounds": [135, 15]
     },
     {
       "name": "Frame Vertical Scrollbar Layer",
-      "position": [135, 0],
+      "position": [145, 10],
       "bounds": [15, 135]
     },
     {
       "name": "Frame Scroll Corner Layer",
-      "position": [135, 135],
+      "position": [145, 145],
       "bounds": [15, 15],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/compositing/force-compositing-mode/overflow-iframe-layer-expected.txt b/third_party/WebKit/LayoutTests/compositing/force-compositing-mode/overflow-iframe-layer-expected.txt
index 60bd49fe..e53be9e7 100644
--- a/third_party/WebKit/LayoutTests/compositing/force-compositing-mode/overflow-iframe-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/force-compositing-mode/overflow-iframe-layer-expected.txt
@@ -15,38 +15,42 @@
     },
     {
       "name": "Frame Overflow Controls Host Layer",
-      "position": [2, 2],
+      "position": [10, 10],
       "bounds": [150, 150]
     },
     {
       "name": "Frame Clipping Layer",
+      "position": [10, 10],
       "bounds": [135, 135]
     },
     {
-      "name": "Frame Scrolling Layer"
+      "name": "Frame Scrolling Layer",
+      "position": [10, 10]
     },
     {
       "name": "Content Root Layer",
+      "position": [10, 10],
       "bounds": [508, 516]
     },
     {
       "name": "LayoutView #document",
+      "position": [10, 10],
       "bounds": [508, 516],
       "drawsContent": true
     },
     {
       "name": "Frame Horizontal Scrollbar Layer",
-      "position": [0, 135],
+      "position": [10, 145],
       "bounds": [135, 15]
     },
     {
       "name": "Frame Vertical Scrollbar Layer",
-      "position": [135, 0],
+      "position": [145, 10],
       "bounds": [15, 135]
     },
     {
       "name": "Frame Scroll Corner Layer",
-      "position": [135, 135],
+      "position": [145, 145],
       "bounds": [15, 15],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/compositing/geometry/ancestor-overflow-change-expected.png b/third_party/WebKit/LayoutTests/compositing/geometry/ancestor-overflow-change-expected.png
deleted file mode 100644
index 317f1b75..0000000
--- a/third_party/WebKit/LayoutTests/compositing/geometry/ancestor-overflow-change-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/compositing/geometry/ancestor-overflow-change-expected.txt b/third_party/WebKit/LayoutTests/compositing/geometry/ancestor-overflow-change-expected.txt
index 0259331..a8a3401 100644
--- a/third_party/WebKit/LayoutTests/compositing/geometry/ancestor-overflow-change-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/geometry/ancestor-overflow-change-expected.txt
@@ -13,6 +13,12 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#008000",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
diff --git a/third_party/WebKit/LayoutTests/compositing/geometry/bounds-clipped-composited-child-expected.txt b/third_party/WebKit/LayoutTests/compositing/geometry/bounds-clipped-composited-child-expected.txt
index cf273535..d2a762b 100644
--- a/third_party/WebKit/LayoutTests/compositing/geometry/bounds-clipped-composited-child-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/geometry/bounds-clipped-composited-child-expected.txt
@@ -9,9 +9,14 @@
     {
       "name": "LayoutBlockFlow DIV class='container'",
       "position": [58, 8],
-      "transformOrigin": [50, 50],
       "bounds": [200, 100],
       "drawsContent": true,
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
diff --git a/third_party/WebKit/LayoutTests/compositing/geometry/bounds-ignores-hidden-dynamic-expected.png b/third_party/WebKit/LayoutTests/compositing/geometry/bounds-ignores-hidden-dynamic-expected.png
index 3ae91667..e1f48b13 100644
--- a/third_party/WebKit/LayoutTests/compositing/geometry/bounds-ignores-hidden-dynamic-expected.png
+++ b/third_party/WebKit/LayoutTests/compositing/geometry/bounds-ignores-hidden-dynamic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/compositing/geometry/bounds-ignores-hidden-dynamic-expected.txt b/third_party/WebKit/LayoutTests/compositing/geometry/bounds-ignores-hidden-dynamic-expected.txt
index 4fbfff4..3e076a9 100644
--- a/third_party/WebKit/LayoutTests/compositing/geometry/bounds-ignores-hidden-dynamic-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/geometry/bounds-ignores-hidden-dynamic-expected.txt
@@ -10,14 +10,12 @@
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited'",
       "position": [10, 10],
-      "transformOrigin": [-10, -10],
       "bounds": [540, 240],
       "drawsContent": true
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited'",
       "position": [10, 260],
-      "transformOrigin": [-10, -10],
       "bounds": [50, 50],
       "contentsOpaque": true,
       "drawsContent": true
diff --git a/third_party/WebKit/LayoutTests/compositing/geometry/bounds-ignores-hidden-dynamic-negzindex-expected.txt b/third_party/WebKit/LayoutTests/compositing/geometry/bounds-ignores-hidden-dynamic-negzindex-expected.txt
index c6b784d..9effd29 100644
--- a/third_party/WebKit/LayoutTests/compositing/geometry/bounds-ignores-hidden-dynamic-negzindex-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/geometry/bounds-ignores-hidden-dynamic-negzindex-expected.txt
@@ -10,18 +10,15 @@
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited'",
-      "transformOrigin": [50, 50],
       "bounds": [500, 250],
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited'",
       "position": [0, 250],
-      "transformOrigin": [50, 50],
       "bounds": [150, 150],
       "drawsContent": true
     },
diff --git a/third_party/WebKit/LayoutTests/compositing/geometry/bounds-ignores-hidden-expected.txt b/third_party/WebKit/LayoutTests/compositing/geometry/bounds-ignores-hidden-expected.txt
index c337c38..eac675d7 100644
--- a/third_party/WebKit/LayoutTests/compositing/geometry/bounds-ignores-hidden-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/geometry/bounds-ignores-hidden-expected.txt
@@ -10,7 +10,6 @@
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited'",
       "position": [10, 10],
-      "transformOrigin": [-10, -10],
       "bounds": [50, 50],
       "contentsOpaque": true,
       "drawsContent": true
diff --git a/third_party/WebKit/LayoutTests/compositing/geometry/clip-expected.txt b/third_party/WebKit/LayoutTests/compositing/geometry/clip-expected.txt
index 08ba06be..db2fc62 100644
--- a/third_party/WebKit/LayoutTests/compositing/geometry/clip-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/geometry/clip-expected.txt
@@ -14,6 +14,25 @@
       "bounds": [110, 110],
       "drawsContent": true,
       "backgroundColor": "#808080",
+      "transform": 1
+    },
+    {
+      "name": "Ancestor Clipping Layer",
+      "position": [215, 15],
+      "bounds": [110, 110]
+    },
+    {
+      "name": "LayoutBlockFlow (relative positioned) DIV class='composited inner'",
+      "position": [-5, -5],
+      "bounds": [120, 120],
+      "drawsContent": true,
+      "backgroundColor": "#00000033",
+      "transform": 2
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
@@ -22,17 +41,7 @@
       ]
     },
     {
-      "name": "Ancestor Clipping Layer",
-      "position": [215, 15],
-      "bounds": [110, 110],
-      "shouldFlattenTransform": false
-    },
-    {
-      "name": "LayoutBlockFlow (relative positioned) DIV class='composited inner'",
-      "position": [-5, -5],
-      "bounds": [120, 120],
-      "drawsContent": true,
-      "backgroundColor": "#00000033",
+      "id": 2,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
diff --git a/third_party/WebKit/LayoutTests/compositing/geometry/clip-inside-expected.txt b/third_party/WebKit/LayoutTests/compositing/geometry/clip-inside-expected.txt
index 200b65b..f8e42b3 100644
--- a/third_party/WebKit/LayoutTests/compositing/geometry/clip-inside-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/geometry/clip-inside-expected.txt
@@ -11,11 +11,29 @@
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited box'",
       "position": [25, 35],
-      "transformOrigin": [45, 35],
       "bounds": [90, 80],
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#808080",
+      "transform": 1
+    },
+    {
+      "name": "Ancestor Clipping Layer",
+      "position": [225, 35],
+      "bounds": [90, 80]
+    },
+    {
+      "name": "LayoutBlockFlow (relative positioned) DIV class='composited inner'",
+      "position": [-15, -25],
+      "bounds": [120, 120],
+      "drawsContent": true,
+      "backgroundColor": "#00000033",
+      "transform": 2
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
@@ -24,17 +42,7 @@
       ]
     },
     {
-      "name": "Ancestor Clipping Layer",
-      "position": [225, 35],
-      "bounds": [90, 80],
-      "shouldFlattenTransform": false
-    },
-    {
-      "name": "LayoutBlockFlow (relative positioned) DIV class='composited inner'",
-      "position": [-15, -25],
-      "bounds": [120, 120],
-      "drawsContent": true,
-      "backgroundColor": "#00000033",
+      "id": 2,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
diff --git a/third_party/WebKit/LayoutTests/compositing/geometry/clip-with-shadow-expected.txt b/third_party/WebKit/LayoutTests/compositing/geometry/clip-with-shadow-expected.txt
index 71c872cd..60a544d 100644
--- a/third_party/WebKit/LayoutTests/compositing/geometry/clip-with-shadow-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/geometry/clip-with-shadow-expected.txt
@@ -12,6 +12,25 @@
       "bounds": [110, 110],
       "drawsContent": true,
       "backgroundColor": "#808080",
+      "transform": 1
+    },
+    {
+      "name": "Ancestor Clipping Layer",
+      "position": [215, 15],
+      "bounds": [110, 110]
+    },
+    {
+      "name": "LayoutBlockFlow (relative positioned) DIV class='composited inner'",
+      "position": [-5, -5],
+      "bounds": [120, 120],
+      "drawsContent": true,
+      "backgroundColor": "#00000033",
+      "transform": 2
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
@@ -20,17 +39,7 @@
       ]
     },
     {
-      "name": "Ancestor Clipping Layer",
-      "position": [215, 15],
-      "bounds": [110, 110],
-      "shouldFlattenTransform": false
-    },
-    {
-      "name": "LayoutBlockFlow (relative positioned) DIV class='composited inner'",
-      "position": [-5, -5],
-      "bounds": [120, 120],
-      "drawsContent": true,
-      "backgroundColor": "#00000033",
+      "id": 2,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
diff --git a/third_party/WebKit/LayoutTests/compositing/geometry/flipped-writing-mode-expected.png b/third_party/WebKit/LayoutTests/compositing/geometry/flipped-writing-mode-expected.png
index 7a7a244..68edd8f 100644
--- a/third_party/WebKit/LayoutTests/compositing/geometry/flipped-writing-mode-expected.png
+++ b/third_party/WebKit/LayoutTests/compositing/geometry/flipped-writing-mode-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/compositing/geometry/flipped-writing-mode-expected.txt b/third_party/WebKit/LayoutTests/compositing/geometry/flipped-writing-mode-expected.txt
index 5c09ff0..8cbf1ed1 100644
--- a/third_party/WebKit/LayoutTests/compositing/geometry/flipped-writing-mode-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/geometry/flipped-writing-mode-expected.txt
@@ -16,8 +16,7 @@
     },
     {
       "name": "LayoutBlockFlow DIV class='composited box'",
-      "position": [35, 10],
-      "transformOrigin": [145, 50],
+      "position": [53, 20],
       "bounds": [195, 100],
       "drawsContent": true,
       "backgroundColor": "#0000FF"
diff --git a/third_party/WebKit/LayoutTests/compositing/geometry/foreground-layer-expected.txt b/third_party/WebKit/LayoutTests/compositing/geometry/foreground-layer-expected.txt
index cbd9a2e..112fd0d 100644
--- a/third_party/WebKit/LayoutTests/compositing/geometry/foreground-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/geometry/foreground-layer-expected.txt
@@ -18,15 +18,11 @@
       "name": "LayoutBlockFlow (positioned) DIV class='negative child'",
       "position": [59, 59],
       "bounds": [50, 50],
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [0, 0, 1, 1]
-      ]
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='main box' (foreground) Layer",
+      "position": [19, 89],
       "bounds": [318, 318],
       "drawsContent": true
     },
@@ -39,12 +35,24 @@
     },
     {
       "name": "Child Containment Layer",
-      "position": [59, 59],
+      "position": [422, 78],
       "bounds": [200, 200]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='negative child'",
       "bounds": [50, 50],
+      "transform": 2
+    },
+    {
+      "name": "LayoutBlockFlow (relative positioned) DIV class='main box' (foreground) Layer",
+      "position": [422, 78],
+      "bounds": [200, 200],
+      "drawsContent": true
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
@@ -53,9 +61,13 @@
       ]
     },
     {
-      "name": "LayoutBlockFlow (relative positioned) DIV class='main box' (foreground) Layer",
-      "bounds": [200, 200],
-      "drawsContent": true
+      "id": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, 1, 1]
+      ]
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/compositing/geometry/limit-layer-bounds-opacity-transition-expected.txt b/third_party/WebKit/LayoutTests/compositing/geometry/limit-layer-bounds-opacity-transition-expected.txt
index f9410cb..72b425a 100644
--- a/third_party/WebKit/LayoutTests/compositing/geometry/limit-layer-bounds-opacity-transition-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/geometry/limit-layer-bounds-opacity-transition-expected.txt
@@ -9,8 +9,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow DIV class='compositing'",
diff --git a/third_party/WebKit/LayoutTests/compositing/geometry/limit-layer-bounds-positioned-expected.txt b/third_party/WebKit/LayoutTests/compositing/geometry/limit-layer-bounds-positioned-expected.txt
index 6a24fbc..e8671da 100644
--- a/third_party/WebKit/LayoutTests/compositing/geometry/limit-layer-bounds-positioned-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/geometry/limit-layer-bounds-positioned-expected.txt
@@ -8,8 +8,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='compositing'",
diff --git a/third_party/WebKit/LayoutTests/compositing/geometry/limit-layer-bounds-positioned-transition-expected.txt b/third_party/WebKit/LayoutTests/compositing/geometry/limit-layer-bounds-positioned-transition-expected.txt
index ac694b2..3057116 100644
--- a/third_party/WebKit/LayoutTests/compositing/geometry/limit-layer-bounds-positioned-transition-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/geometry/limit-layer-bounds-positioned-transition-expected.txt
@@ -8,8 +8,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='compositing'",
diff --git a/third_party/WebKit/LayoutTests/compositing/geometry/limit-layer-bounds-transformed-expected.txt b/third_party/WebKit/LayoutTests/compositing/geometry/limit-layer-bounds-transformed-expected.txt
index 04bbbb5f4a..28e3e552 100644
--- a/third_party/WebKit/LayoutTests/compositing/geometry/limit-layer-bounds-transformed-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/geometry/limit-layer-bounds-transformed-expected.txt
@@ -8,8 +8,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='compositing'",
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/become-composited-nested-iframes-expected.txt b/third_party/WebKit/LayoutTests/compositing/iframes/become-composited-nested-iframes-expected.txt
index f3c4ce5d..7e39dc7 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/become-composited-nested-iframes-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/become-composited-nested-iframes-expected.txt
@@ -15,56 +15,64 @@
     },
     {
       "name": "Frame Overflow Controls Host Layer",
-      "position": [2, 2],
+      "position": [22, 122],
       "bounds": [280, 200]
     },
     {
       "name": "Frame Clipping Layer",
+      "position": [22, 122],
       "bounds": [280, 200]
     },
     {
-      "name": "Frame Scrolling Layer"
+      "name": "Frame Scrolling Layer",
+      "position": [22, 122]
     },
     {
       "name": "Content Root Layer",
+      "position": [22, 122],
       "bounds": [280, 200]
     },
     {
       "name": "LayoutView #document",
+      "position": [22, 122],
       "bounds": [280, 200],
       "drawsContent": true
     },
     {
       "name": "LayoutIFrame IFRAME",
-      "position": [8, 8],
+      "position": [30, 130],
       "bounds": [252, 172],
       "drawsContent": true
     },
     {
       "name": "Frame Overflow Controls Host Layer",
-      "position": [1, 1],
+      "position": [31, 131],
       "bounds": [250, 170]
     },
     {
       "name": "Frame Clipping Layer",
+      "position": [31, 131],
       "bounds": [250, 170]
     },
     {
-      "name": "Frame Scrolling Layer"
+      "name": "Frame Scrolling Layer",
+      "position": [31, 131]
     },
     {
       "name": "Content Root Layer",
+      "position": [31, 131],
       "bounds": [250, 230]
     },
     {
       "name": "LayoutView #document",
+      "position": [31, 131],
       "bounds": [250, 230],
       "drawsContent": true,
       "backgroundColor": "#C0C0C0"
     },
     {
       "name": "LayoutBlockFlow DIV id='iframe-content' class='box'",
-      "position": [18, 10],
+      "position": [49, 141],
       "bounds": [210, 210],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -78,56 +86,64 @@
     },
     {
       "name": "Frame Overflow Controls Host Layer",
-      "position": [2, 2],
+      "position": [22, 346],
       "bounds": [280, 200]
     },
     {
       "name": "Frame Clipping Layer",
+      "position": [22, 346],
       "bounds": [280, 200]
     },
     {
-      "name": "Frame Scrolling Layer"
+      "name": "Frame Scrolling Layer",
+      "position": [22, 346]
     },
     {
       "name": "Content Root Layer",
+      "position": [22, 346],
       "bounds": [280, 200]
     },
     {
       "name": "LayoutView #document",
+      "position": [22, 346],
       "bounds": [280, 200],
       "drawsContent": true
     },
     {
       "name": "LayoutIFrame IFRAME",
-      "position": [8, 8],
+      "position": [30, 354],
       "bounds": [252, 172],
       "drawsContent": true
     },
     {
       "name": "Frame Overflow Controls Host Layer",
-      "position": [1, 1],
+      "position": [31, 355],
       "bounds": [250, 170]
     },
     {
       "name": "Frame Clipping Layer",
+      "position": [31, 355],
       "bounds": [250, 170]
     },
     {
-      "name": "Frame Scrolling Layer"
+      "name": "Frame Scrolling Layer",
+      "position": [31, 355]
     },
     {
       "name": "Content Root Layer",
+      "position": [31, 355],
       "bounds": [250, 230]
     },
     {
       "name": "LayoutView #document",
+      "position": [31, 355],
       "bounds": [250, 230],
       "drawsContent": true,
       "backgroundColor": "#C0C0C0"
     },
     {
       "name": "LayoutBlockFlow DIV id='iframe-content' class='box'",
-      "position": [18, 10],
+      "position": [49, 365],
       "bounds": [210, 210],
       "contentsOpaque": true,
       "drawsContent": true,
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/become-overlapped-iframe-expected.txt b/third_party/WebKit/LayoutTests/compositing/iframes/become-overlapped-iframe-expected.txt
index eb3e0a3..12fa4404 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/become-overlapped-iframe-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/become-overlapped-iframe-expected.txt
@@ -15,29 +15,33 @@
     },
     {
       "name": "Frame Overflow Controls Host Layer",
-      "position": [15, 15],
+      "position": [73, 73],
       "bounds": [320, 170]
     },
     {
       "name": "Frame Clipping Layer",
+      "position": [73, 73],
       "bounds": [305, 170]
     },
     {
-      "name": "Frame Scrolling Layer"
+      "name": "Frame Scrolling Layer",
+      "position": [73, 73]
     },
     {
       "name": "Content Root Layer",
+      "position": [73, 73],
       "bounds": [305, 230]
     },
     {
       "name": "LayoutView #document",
+      "position": [73, 73],
       "bounds": [305, 230],
       "drawsContent": true,
       "backgroundColor": "#C0C0C0"
     },
     {
       "name": "LayoutBlockFlow DIV id='iframe-content' class='box'",
-      "position": [18, 10],
+      "position": [91, 83],
       "bounds": [210, 210],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -45,7 +49,7 @@
     },
     {
       "name": "Frame Vertical Scrollbar Layer",
-      "position": [305, 0],
+      "position": [378, 73],
       "bounds": [15, 170]
     },
     {
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/composited-parent-iframe-expected.txt b/third_party/WebKit/LayoutTests/compositing/iframes/composited-parent-iframe-expected.txt
index 675ba9d..f21be61 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/composited-parent-iframe-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/composited-parent-iframe-expected.txt
@@ -15,29 +15,33 @@
     },
     {
       "name": "Frame Overflow Controls Host Layer",
-      "position": [34, 34],
+      "position": [23, 23],
       "bounds": [300, 150]
     },
     {
       "name": "Frame Clipping Layer",
+      "position": [23, 23],
       "bounds": [285, 150]
     },
     {
-      "name": "Frame Scrolling Layer"
+      "name": "Frame Scrolling Layer",
+      "position": [23, 23]
     },
     {
       "name": "Content Root Layer",
+      "position": [23, 23],
       "bounds": [285, 230]
     },
     {
       "name": "LayoutView #document",
+      "position": [23, 23],
       "bounds": [285, 230],
       "drawsContent": true,
       "backgroundColor": "#C0C0C0"
     },
     {
       "name": "LayoutBlockFlow DIV id='iframe-content' class='box'",
-      "position": [18, 10],
+      "position": [41, 33],
       "bounds": [210, 210],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -45,7 +49,7 @@
     },
     {
       "name": "Frame Vertical Scrollbar Layer",
-      "position": [285, 0],
+      "position": [308, 23],
       "bounds": [15, 150]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe-delayed-expected.txt b/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe-delayed-expected.txt
index 575f71f..77f781f 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe-delayed-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe-delayed-expected.txt
@@ -17,29 +17,33 @@
     },
     {
       "name": "Frame Overflow Controls Host Layer",
-      "position": [34, 34],
+      "position": [43, 143],
       "bounds": [300, 150]
     },
     {
       "name": "Frame Clipping Layer",
+      "position": [43, 143],
       "bounds": [285, 150]
     },
     {
-      "name": "Frame Scrolling Layer"
+      "name": "Frame Scrolling Layer",
+      "position": [43, 143]
     },
     {
       "name": "Content Root Layer",
+      "position": [43, 143],
       "bounds": [285, 230]
     },
     {
       "name": "LayoutView #document",
+      "position": [43, 143],
       "bounds": [285, 230],
       "drawsContent": true,
       "backgroundColor": "#C0C0C0"
     },
     {
       "name": "LayoutBlockFlow DIV id='iframe-content' class='box'",
-      "position": [18, 10],
+      "position": [61, 153],
       "bounds": [210, 210],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -47,7 +51,7 @@
     },
     {
       "name": "Frame Vertical Scrollbar Layer",
-      "position": [285, 0],
+      "position": [328, 143],
       "bounds": [15, 150]
     },
     {
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe-expected.txt b/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe-expected.txt
index 6915aba..f972f25 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe-expected.txt
@@ -15,29 +15,33 @@
     },
     {
       "name": "Frame Overflow Controls Host Layer",
-      "position": [34, 34],
+      "position": [43, 43],
       "bounds": [300, 150]
     },
     {
       "name": "Frame Clipping Layer",
+      "position": [43, 43],
       "bounds": [285, 150]
     },
     {
-      "name": "Frame Scrolling Layer"
+      "name": "Frame Scrolling Layer",
+      "position": [43, 43]
     },
     {
       "name": "Content Root Layer",
+      "position": [43, 43],
       "bounds": [285, 230]
     },
     {
       "name": "LayoutView #document",
+      "position": [43, 43],
       "bounds": [285, 230],
       "drawsContent": true,
       "backgroundColor": "#C0C0C0"
     },
     {
       "name": "LayoutBlockFlow DIV id='test' class='composited box'",
-      "position": [18, 10],
+      "position": [61, 53],
       "bounds": [210, 210],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -45,7 +49,7 @@
     },
     {
       "name": "Frame Vertical Scrollbar Layer",
-      "position": [285, 0],
+      "position": [328, 43],
       "bounds": [15, 150]
     },
     {
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe2-expected.txt b/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe2-expected.txt
index badbdae..d3754d5 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe2-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe2-expected.txt
@@ -15,29 +15,33 @@
     },
     {
       "name": "Frame Overflow Controls Host Layer",
-      "position": [34, 34],
+      "position": [43, 43],
       "bounds": [300, 150]
     },
     {
       "name": "Frame Clipping Layer",
+      "position": [43, 43],
       "bounds": [285, 150]
     },
     {
-      "name": "Frame Scrolling Layer"
+      "name": "Frame Scrolling Layer",
+      "position": [43, 43]
     },
     {
       "name": "Content Root Layer",
+      "position": [43, 43],
       "bounds": [285, 230]
     },
     {
       "name": "LayoutView #document",
+      "position": [43, 43],
       "bounds": [285, 230],
       "drawsContent": true,
       "backgroundColor": "#C0C0C0"
     },
     {
       "name": "LayoutBlockFlow DIV id='iframe-content' class='box'",
-      "position": [18, 10],
+      "position": [61, 53],
       "bounds": [210, 210],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -45,7 +49,7 @@
     },
     {
       "name": "Frame Vertical Scrollbar Layer",
-      "position": [285, 0],
+      "position": [328, 43],
       "bounds": [15, 150]
     },
     {
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe3-expected.txt b/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe3-expected.txt
index e39264b9..51ee5a7 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe3-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe3-expected.txt
@@ -15,29 +15,33 @@
     },
     {
       "name": "Frame Overflow Controls Host Layer",
-      "position": [34, 34],
+      "position": [43, 43],
       "bounds": [300, 150]
     },
     {
       "name": "Frame Clipping Layer",
+      "position": [43, 43],
       "bounds": [285, 150]
     },
     {
-      "name": "Frame Scrolling Layer"
+      "name": "Frame Scrolling Layer",
+      "position": [43, 43]
     },
     {
       "name": "Content Root Layer",
+      "position": [43, 43],
       "bounds": [285, 230]
     },
     {
       "name": "LayoutView #document",
+      "position": [43, 43],
       "bounds": [285, 230],
       "drawsContent": true,
       "backgroundColor": "#C0C0C0"
     },
     {
       "name": "LayoutBlockFlow DIV id='iframe-content' class='box'",
-      "position": [18, 10],
+      "position": [61, 53],
       "bounds": [210, 210],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -45,7 +49,7 @@
     },
     {
       "name": "Frame Vertical Scrollbar Layer",
-      "position": [285, 0],
+      "position": [328, 43],
       "bounds": [15, 150]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/enter-compositing-iframe-expected.txt b/third_party/WebKit/LayoutTests/compositing/iframes/enter-compositing-iframe-expected.txt
index 6915aba..f972f25 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/enter-compositing-iframe-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/enter-compositing-iframe-expected.txt
@@ -15,29 +15,33 @@
     },
     {
       "name": "Frame Overflow Controls Host Layer",
-      "position": [34, 34],
+      "position": [43, 43],
       "bounds": [300, 150]
     },
     {
       "name": "Frame Clipping Layer",
+      "position": [43, 43],
       "bounds": [285, 150]
     },
     {
-      "name": "Frame Scrolling Layer"
+      "name": "Frame Scrolling Layer",
+      "position": [43, 43]
     },
     {
       "name": "Content Root Layer",
+      "position": [43, 43],
       "bounds": [285, 230]
     },
     {
       "name": "LayoutView #document",
+      "position": [43, 43],
       "bounds": [285, 230],
       "drawsContent": true,
       "backgroundColor": "#C0C0C0"
     },
     {
       "name": "LayoutBlockFlow DIV id='test' class='composited box'",
-      "position": [18, 10],
+      "position": [61, 53],
       "bounds": [210, 210],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -45,7 +49,7 @@
     },
     {
       "name": "Frame Vertical Scrollbar Layer",
-      "position": [285, 0],
+      "position": [328, 43],
       "bounds": [15, 150]
     },
     {
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/iframe-resize-expected.txt b/third_party/WebKit/LayoutTests/compositing/iframes/iframe-resize-expected.txt
index b9cc39ef..1dab109 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/iframe-resize-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/iframe-resize-expected.txt
@@ -15,29 +15,33 @@
     },
     {
       "name": "Frame Overflow Controls Host Layer",
-      "position": [34, 34],
+      "position": [43, 43],
       "bounds": [400, 120]
     },
     {
       "name": "Frame Clipping Layer",
+      "position": [43, 43],
       "bounds": [385, 120]
     },
     {
-      "name": "Frame Scrolling Layer"
+      "name": "Frame Scrolling Layer",
+      "position": [43, 43]
     },
     {
       "name": "Content Root Layer",
+      "position": [43, 43],
       "bounds": [385, 230]
     },
     {
       "name": "LayoutView #document",
+      "position": [43, 43],
       "bounds": [385, 230],
       "drawsContent": true,
       "backgroundColor": "#C0C0C0"
     },
     {
       "name": "LayoutBlockFlow DIV id='iframe-content' class='box'",
-      "position": [18, 10],
+      "position": [61, 53],
       "bounds": [210, 210],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -45,7 +49,7 @@
     },
     {
       "name": "Frame Vertical Scrollbar Layer",
-      "position": [385, 0],
+      "position": [428, 43],
       "bounds": [15, 120]
     },
     {
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/iframe-size-from-zero-expected.txt b/third_party/WebKit/LayoutTests/compositing/iframes/iframe-size-from-zero-expected.txt
index c1c50cf8..73aa1e4 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/iframe-size-from-zero-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/iframe-size-from-zero-expected.txt
@@ -15,29 +15,33 @@
     },
     {
       "name": "Frame Overflow Controls Host Layer",
-      "position": [15, 15],
+      "position": [43, 43],
       "bounds": [300, 150]
     },
     {
       "name": "Frame Clipping Layer",
+      "position": [43, 43],
       "bounds": [285, 150]
     },
     {
-      "name": "Frame Scrolling Layer"
+      "name": "Frame Scrolling Layer",
+      "position": [43, 43]
     },
     {
       "name": "Content Root Layer",
+      "position": [43, 43],
       "bounds": [285, 230]
     },
     {
       "name": "LayoutView #document",
+      "position": [43, 43],
       "bounds": [285, 230],
       "drawsContent": true,
       "backgroundColor": "#C0C0C0"
     },
     {
       "name": "LayoutBlockFlow DIV id='iframe-content' class='box'",
-      "position": [18, 10],
+      "position": [61, 53],
       "bounds": [210, 210],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -45,7 +49,7 @@
     },
     {
       "name": "Frame Vertical Scrollbar Layer",
-      "position": [285, 0],
+      "position": [328, 43],
       "bounds": [15, 150]
     },
     {
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/overlapped-iframe-expected.txt b/third_party/WebKit/LayoutTests/compositing/iframes/overlapped-iframe-expected.txt
index e07793e1..bff81ec9 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/overlapped-iframe-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/overlapped-iframe-expected.txt
@@ -15,29 +15,33 @@
     },
     {
       "name": "Frame Overflow Controls Host Layer",
-      "position": [34, 34],
+      "position": [43, 43],
       "bounds": [300, 150]
     },
     {
       "name": "Frame Clipping Layer",
+      "position": [43, 43],
       "bounds": [285, 150]
     },
     {
-      "name": "Frame Scrolling Layer"
+      "name": "Frame Scrolling Layer",
+      "position": [43, 43]
     },
     {
       "name": "Content Root Layer",
+      "position": [43, 43],
       "bounds": [285, 230]
     },
     {
       "name": "LayoutView #document",
+      "position": [43, 43],
       "bounds": [285, 230],
       "drawsContent": true,
       "backgroundColor": "#C0C0C0"
     },
     {
       "name": "LayoutBlockFlow DIV id='iframe-content' class='box'",
-      "position": [18, 10],
+      "position": [61, 53],
       "bounds": [210, 210],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -45,7 +49,7 @@
     },
     {
       "name": "Frame Vertical Scrollbar Layer",
-      "position": [285, 0],
+      "position": [328, 43],
       "bounds": [15, 150]
     },
     {
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/overlapped-iframe-iframe-expected.txt b/third_party/WebKit/LayoutTests/compositing/iframes/overlapped-iframe-iframe-expected.txt
index 8026f9c46..1654c19 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/overlapped-iframe-iframe-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/overlapped-iframe-iframe-expected.txt
@@ -18,24 +18,28 @@
     },
     {
       "name": "Frame Clipping Layer",
+      "position": [2, 2],
       "bounds": [300, 300]
     },
     {
-      "name": "Frame Scrolling Layer"
+      "name": "Frame Scrolling Layer",
+      "position": [2, 2]
     },
     {
       "name": "Content Root Layer",
+      "position": [2, 2],
       "bounds": [300, 300]
     },
     {
       "name": "LayoutView #document",
+      "position": [2, 2],
       "bounds": [300, 300],
       "drawsContent": true,
       "backgroundColor": "#C0C0C0"
     },
     {
       "name": "LayoutBlockFlow DIV id='iframe-content' class='box'",
-      "position": [18, 10],
+      "position": [20, 12],
       "bounds": [210, 210],
       "contentsOpaque": true,
       "drawsContent": true,
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/overlapped-nested-iframes-expected.txt b/third_party/WebKit/LayoutTests/compositing/iframes/overlapped-nested-iframes-expected.txt
index ba05ce15..a1ed710 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/overlapped-nested-iframes-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/overlapped-nested-iframes-expected.txt
@@ -15,56 +15,64 @@
     },
     {
       "name": "Frame Overflow Controls Host Layer",
-      "position": [2, 2],
+      "position": [22, 152],
       "bounds": [280, 200]
     },
     {
       "name": "Frame Clipping Layer",
+      "position": [22, 152],
       "bounds": [280, 200]
     },
     {
-      "name": "Frame Scrolling Layer"
+      "name": "Frame Scrolling Layer",
+      "position": [22, 152]
     },
     {
       "name": "Content Root Layer",
+      "position": [22, 152],
       "bounds": [280, 200]
     },
     {
       "name": "LayoutView #document",
+      "position": [22, 152],
       "bounds": [280, 200],
       "drawsContent": true
     },
     {
       "name": "LayoutIFrame IFRAME",
-      "position": [8, 8],
+      "position": [30, 160],
       "bounds": [252, 172],
       "drawsContent": true
     },
     {
       "name": "Frame Overflow Controls Host Layer",
-      "position": [1, 1],
+      "position": [31, 161],
       "bounds": [250, 170]
     },
     {
       "name": "Frame Clipping Layer",
+      "position": [31, 161],
       "bounds": [250, 170]
     },
     {
-      "name": "Frame Scrolling Layer"
+      "name": "Frame Scrolling Layer",
+      "position": [31, 161]
     },
     {
       "name": "Content Root Layer",
+      "position": [31, 161],
       "bounds": [250, 230]
     },
     {
       "name": "LayoutView #document",
+      "position": [31, 161],
       "bounds": [250, 230],
       "drawsContent": true,
       "backgroundColor": "#C0C0C0"
     },
     {
       "name": "LayoutBlockFlow DIV id='iframe-content' class='box'",
-      "position": [18, 10],
+      "position": [49, 171],
       "bounds": [210, 210],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -78,56 +86,64 @@
     },
     {
       "name": "Frame Overflow Controls Host Layer",
-      "position": [2, 2],
+      "position": [22, 376],
       "bounds": [280, 200]
     },
     {
       "name": "Frame Clipping Layer",
+      "position": [22, 376],
       "bounds": [280, 200]
     },
     {
-      "name": "Frame Scrolling Layer"
+      "name": "Frame Scrolling Layer",
+      "position": [22, 376]
     },
     {
       "name": "Content Root Layer",
+      "position": [22, 376],
       "bounds": [280, 200]
     },
     {
       "name": "LayoutView #document",
+      "position": [22, 376],
       "bounds": [280, 200],
       "drawsContent": true
     },
     {
       "name": "LayoutIFrame IFRAME",
-      "position": [8, 8],
+      "position": [30, 384],
       "bounds": [252, 172],
       "drawsContent": true
     },
     {
       "name": "Frame Overflow Controls Host Layer",
-      "position": [1, 1],
+      "position": [31, 385],
       "bounds": [250, 170]
     },
     {
       "name": "Frame Clipping Layer",
+      "position": [31, 385],
       "bounds": [250, 170]
     },
     {
-      "name": "Frame Scrolling Layer"
+      "name": "Frame Scrolling Layer",
+      "position": [31, 385]
     },
     {
       "name": "Content Root Layer",
+      "position": [31, 385],
       "bounds": [250, 230]
     },
     {
       "name": "LayoutView #document",
+      "position": [31, 385],
       "bounds": [250, 230],
       "drawsContent": true,
       "backgroundColor": "#C0C0C0"
     },
     {
       "name": "LayoutBlockFlow DIV id='iframe-content' class='box'",
-      "position": [18, 10],
+      "position": [49, 395],
       "bounds": [210, 210],
       "contentsOpaque": true,
       "drawsContent": true,
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/resizer-expected.txt b/third_party/WebKit/LayoutTests/compositing/iframes/resizer-expected.txt
index 02e04a5..873d572 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/resizer-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/resizer-expected.txt
@@ -15,29 +15,33 @@
     },
     {
       "name": "Frame Overflow Controls Host Layer",
-      "position": [2, 2],
+      "position": [10, 10],
       "bounds": [300, 150]
     },
     {
       "name": "Frame Clipping Layer",
+      "position": [10, 10],
       "bounds": [285, 150]
     },
     {
-      "name": "Frame Scrolling Layer"
+      "name": "Frame Scrolling Layer",
+      "position": [10, 10]
     },
     {
       "name": "Content Root Layer",
+      "position": [10, 10],
       "bounds": [285, 230]
     },
     {
       "name": "LayoutView #document",
+      "position": [10, 10],
       "bounds": [285, 230],
       "drawsContent": true,
       "backgroundColor": "#C0C0C0"
     },
     {
       "name": "LayoutBlockFlow DIV id='iframe-content' class='box'",
-      "position": [18, 10],
+      "position": [28, 20],
       "bounds": [210, 210],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -45,16 +49,17 @@
     },
     {
       "name": "Frame Vertical Scrollbar Layer",
-      "position": [285, 0],
+      "position": [295, 10],
       "bounds": [15, 150]
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 8],
       "bounds": [304, 154]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [287, 137],
+      "position": [295, 145],
       "bounds": [15, 15],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/scrolling-iframe-expected.txt b/third_party/WebKit/LayoutTests/compositing/iframes/scrolling-iframe-expected.txt
index 4122b5a..890129b 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/scrolling-iframe-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/scrolling-iframe-expected.txt
@@ -15,29 +15,33 @@
     },
     {
       "name": "Frame Overflow Controls Host Layer",
-      "position": [34, 34],
+      "position": [43, 43],
       "bounds": [300, 150]
     },
     {
       "name": "Frame Clipping Layer",
+      "position": [43, 43],
       "bounds": [285, 135]
     },
     {
-      "name": "Frame Scrolling Layer"
+      "name": "Frame Scrolling Layer",
+      "position": [43, 43]
     },
     {
       "name": "Content Root Layer",
+      "position": [43, 43],
       "bounds": [508, 608]
     },
     {
       "name": "LayoutView #document",
+      "position": [43, 43],
       "bounds": [508, 608],
       "drawsContent": true,
       "backgroundColor": "#C0C0C0"
     },
     {
       "name": "LayoutBlockFlow DIV id='iframe-content' class='box'",
-      "position": [108, 100],
+      "position": [151, 143],
       "bounds": [200, 200],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -45,17 +49,17 @@
     },
     {
       "name": "Frame Horizontal Scrollbar Layer",
-      "position": [0, 135],
+      "position": [43, 178],
       "bounds": [285, 15]
     },
     {
       "name": "Frame Vertical Scrollbar Layer",
-      "position": [285, 0],
+      "position": [328, 43],
       "bounds": [15, 135]
     },
     {
       "name": "Frame Scroll Corner Layer",
-      "position": [285, 135],
+      "position": [328, 178],
       "bounds": [15, 15],
       "drawsContent": true
     },
diff --git a/third_party/WebKit/LayoutTests/compositing/images/clip-on-directly-composited-image-expected.txt b/third_party/WebKit/LayoutTests/compositing/images/clip-on-directly-composited-image-expected.txt
index 96e7f667..d07e519 100644
--- a/third_party/WebKit/LayoutTests/compositing/images/clip-on-directly-composited-image-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/images/clip-on-directly-composited-image-expected.txt
@@ -10,7 +10,6 @@
     {
       "name": "LayoutImage (positioned) IMG class='composited'",
       "position": [210, 23],
-      "transformOrigin": [90, 90],
       "bounds": [140, 140],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/animation-overlap-with-children-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/animation-overlap-with-children-expected.txt
index 4a6bbc0..4f3efac 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/animation-overlap-with-children-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/animation-overlap-with-children-expected.txt
@@ -16,11 +16,11 @@
     },
     {
       "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "position": [8, 8]
     },
     {
       "name": "LayoutBlockFlow DIV class='composited banner'",
-      "position": [6, 6],
+      "position": [14, 14],
       "bounds": [250, 50],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -28,7 +28,7 @@
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (positioned) DIV class='test1 box')",
-      "position": [11, 21],
+      "position": [19, 29],
       "bounds": [100, 100],
       "drawsContent": true
     },
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/assumed-overlap-for-inline-transform-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/assumed-overlap-for-inline-transform-expected.txt
index eadd48b3..e4e2734 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/assumed-overlap-for-inline-transform-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/assumed-overlap-for-inline-transform-expected.txt
@@ -7,8 +7,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='box'",
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-in-fixed-overflow-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-in-fixed-overflow-expected.txt
index 1f3c709..a6933a9e 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-in-fixed-overflow-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-in-fixed-overflow-expected.txt
@@ -10,22 +10,22 @@
       "name": "LayoutBlockFlow (positioned) DIV class='overflow fixed'",
       "position": [8, 13],
       "bounds": [800, 600],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [785, 600],
-      "shouldFlattenTransform": false
+      "position": [8, 13],
+      "bounds": [785, 600]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 13],
       "bounds": [785, 1000],
       "drawsContent": true
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='yellow fixed'",
-      "position": [192, 0],
+      "position": [200, 13],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -33,11 +33,12 @@
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 13],
       "bounds": [800, 600]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [785, 0],
+      "position": [793, 13],
       "bounds": [15, 600]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-out-of-view-positioning-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-out-of-view-positioning-expected.txt
index 850b531..712ecbec 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-out-of-view-positioning-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-out-of-view-positioning-expected.txt
@@ -19,6 +19,12 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#C0C0C0",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
@@ -44,6 +50,12 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#C0C0C0",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-under-transform-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-under-transform-expected.txt
index 9370a05..7768fc2b 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-under-transform-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-under-transform-expected.txt
@@ -9,16 +9,10 @@
     {
       "name": "LayoutBlockFlow DIV id='transform'",
       "position": [108, 113],
-      "transformOrigin": [284.5, -100],
       "bounds": [256, 256],
       "contentsOpaque": true,
       "drawsContent": true,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [0, 1000, 0, 1]
-      ]
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='overlap'",
@@ -28,6 +22,17 @@
       "drawsContent": true,
       "backgroundColor": "#008000"
     }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, 1000, 0, 1]
+      ]
+    }
   ]
 }
 
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/overflow-scroll-overlap-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/overflow-scroll-overlap-expected.txt
index b7482d0..925ada4c 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/overflow-scroll-overlap-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/overflow-scroll-overlap-expected.txt
@@ -7,8 +7,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow DIV class='composited'",
@@ -24,12 +23,11 @@
     {
       "name": "Ancestor Clipping Layer",
       "position": [23, 23],
-      "bounds": [285, 200],
-      "shouldFlattenTransform": false
+      "bounds": [285, 200]
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='box'",
-      "position": [20, 6],
+      "position": [43, 29],
       "bounds": [200, 100],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -37,7 +35,7 @@
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (relative positioned) DIV class='box')",
-      "position": [20, 161],
+      "position": [43, 184],
       "bounds": [210, 100],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-animation-clipping-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-animation-clipping-expected.txt
index 096b41f..61057d0 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-animation-clipping-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-animation-clipping-expected.txt
@@ -13,12 +13,7 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#0000FF",
-      "transform": [
-        [...],
-        [...],
-        [...],
-        [...]
-      ]
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='container'",
@@ -30,7 +25,7 @@
     },
     {
       "name": "Child Containment Layer",
-      "position": [1, 1],
+      "position": [59, 231],
       "bounds": [120, 460]
     },
     {
@@ -40,12 +35,7 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#808080",
-      "transform": [
-        [...],
-        [...],
-        [...],
-        [...]
-      ]
+      "transform": 2
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='to-animate2' class='box animating2'",
@@ -54,16 +44,11 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#0000FF",
-      "transform": [
-        [...],
-        [...],
-        [...],
-        [...]
-      ]
+      "transform": 3
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='box yellow'",
-      "position": [10, 340],
+      "position": [69, 571],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -77,6 +62,35 @@
       "drawsContent": true,
       "backgroundColor": "#FFFF00"
     }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [...],
+        [...],
+        [...],
+        [...]
+      ]
+    },
+    {
+      "id": 2,
+      "transform": [
+        [...],
+        [...],
+        [...],
+        [...]
+      ]
+    },
+    {
+      "id": 3,
+      "transform": [
+        [...],
+        [...],
+        [...],
+        [...]
+      ]
+    }
   ]
 }
 
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-animation-container-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-animation-container-expected.txt
index dc0fba3..e413b75 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-animation-container-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-animation-container-expected.txt
@@ -14,12 +14,7 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#0000FF",
-      "transform": [
-        [...],
-        [...],
-        [...],
-        [...]
-      ]
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='container'",
@@ -30,7 +25,7 @@
     },
     {
       "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "position": [47, 230]
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='box gray force-layer'",
@@ -39,6 +34,18 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#808080",
+      "transform": 2
+    },
+    {
+      "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (relative positioned) DIV class='box yellow')",
+      "position": [18, 692],
+      "bounds": [100, 100],
+      "drawsContent": true
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
       "transform": [
         [...],
         [...],
@@ -47,10 +54,13 @@
       ]
     },
     {
-      "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (relative positioned) DIV class='box yellow')",
-      "position": [-29, 462],
-      "bounds": [100, 100],
-      "drawsContent": true
+      "id": 2,
+      "transform": [
+        [...],
+        [...],
+        [...],
+        [...]
+      ]
     }
   ]
 }
@@ -71,12 +81,7 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#0000FF",
-      "transform": [
-        [...],
-        [...],
-        [...],
-        [...]
-      ]
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='container'",
@@ -93,12 +98,7 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#808080",
-      "transform": [
-        [...],
-        [...],
-        [...],
-        [...]
-      ]
+      "transform": 2
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='first-green-box' class='box green rotate-45deg'",
@@ -106,16 +106,11 @@
       "bounds": [102, 102],
       "drawsContent": true,
       "backgroundColor": "#008000",
-      "transform": [
-        [...],
-        [...],
-        [...],
-        [...]
-      ]
+      "transform": 3
     },
     {
       "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "position": [58, 230]
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='box green rotate-45deg'",
@@ -123,6 +118,18 @@
       "bounds": [102, 102],
       "drawsContent": true,
       "backgroundColor": "#008000",
+      "transform": 4
+    },
+    {
+      "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (relative positioned) DIV class='box green')",
+      "position": [18, 570],
+      "bounds": [152, 222],
+      "drawsContent": true
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
       "transform": [
         [...],
         [...],
@@ -131,10 +138,33 @@
       ]
     },
     {
-      "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (relative positioned) DIV class='box green')",
-      "position": [-40, 340],
-      "bounds": [152, 222],
-      "drawsContent": true
+      "id": 2,
+      "transform": [
+        [...],
+        [...],
+        [...],
+        [...]
+      ]
+    },
+    {
+      "id": 3,
+      "transform": [
+        [...],
+        [...],
+        [...],
+        [...]
+      ],
+      "origin": [51, 51]
+    },
+    {
+      "id": 4,
+      "transform": [
+        [...],
+        [...],
+        [...],
+        [...]
+      ],
+      "origin": [51, 51]
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-animation-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-animation-expected.txt
index d29839d3..0e828e8 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-animation-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-animation-expected.txt
@@ -14,7 +14,7 @@
     },
     {
       "name": "Child Containment Layer",
-      "position": [1, 1],
+      "position": [9, 9],
       "bounds": [120, 240]
     },
     {
@@ -24,20 +24,27 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#0000FF",
+      "transform": 1
+    },
+    {
+      "name": "LayoutBlockFlow (relative positioned) DIV class='box'",
+      "position": [19, 129],
+      "bounds": [100, 100],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "backgroundColor": "#0000FF"
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
       "transform": [
         [...],
         [...],
         [...],
         [...]
-      ]
-    },
-    {
-      "name": "LayoutBlockFlow (relative positioned) DIV class='box'",
-      "position": [10, 120],
-      "bounds": [100, 100],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "backgroundColor": "#0000FF"
+      ],
+      "origin": [50, 50]
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-child-layer-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-child-layer-expected.txt
index 1f9f00a1..ae98caa 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-child-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-child-layer-expected.txt
@@ -7,12 +7,10 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='container'",
-      "transformOrigin": [400, 0],
       "bounds": [256, 256],
       "contentsOpaque": true,
       "drawsContent": true
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-clipping-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-clipping-expected.txt
index a12d708..dc8765b38 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-clipping-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-clipping-expected.txt
@@ -9,19 +9,18 @@
     {
       "name": "Ancestor Clipping Layer",
       "position": [50, 50],
-      "bounds": [100, 100],
-      "shouldFlattenTransform": false
+      "bounds": [100, 100]
     },
     {
       "name": "LayoutBlockFlow DIV id='child'",
+      "position": [50, 50],
       "bounds": [500, 100],
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#008000"
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow DIV id='child'",
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transformed-3d-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transformed-3d-expected.txt
index f952ac9..ade0cb3 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transformed-3d-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transformed-3d-expected.txt
@@ -14,6 +14,12 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#008000",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
@@ -34,8 +40,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='green-box' class='box green center composited rotated-3d'",
@@ -44,12 +49,7 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#008000",
-      "transform": [
-        [0.707106781186548, 0.707106781186548, 0, 0],
-        [-0.707106781186548, 0.707106781186548, 0, 0],
-        [0, 0, 1, 0],
-        [0, 0, -1, 1]
-      ]
+      "transform": 1
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (positioned) DIV class='box top left')",
@@ -57,6 +57,18 @@
       "bounds": [300, 300],
       "drawsContent": true
     }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [0.707106781186548, 0.707106781186548, 0, 0],
+        [-0.707106781186548, 0.707106781186548, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, -1, 1]
+      ],
+      "origin": [50, 50]
+    }
   ]
 }
 
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transformed-and-clipped-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transformed-and-clipped-expected.txt
index 0667128..c28f9b54 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transformed-and-clipped-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transformed-and-clipped-expected.txt
@@ -10,32 +10,41 @@
       "name": "LayoutBlockFlow (positioned) DIV class='container clips'",
       "bounds": [100, 100],
       "drawsContent": true,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [110, 0, 0, 1]
-      ]
+      "transform": 1
     },
     {
       "name": "Child Containment Layer",
-      "bounds": [100, 100]
+      "bounds": [100, 100],
+      "transform": 1
     },
     {
       "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='under composited'",
       "bounds": [100, 100],
       "contentsOpaque": true,
       "drawsContent": true,
-      "backgroundColor": "#FF0000"
+      "backgroundColor": "#FF0000",
+      "transform": 1
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (positioned) DIV class='over')",
       "bounds": [100, 100],
-      "drawsContent": true
+      "drawsContent": true,
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [110, 0, 0, 1]
+      ]
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transformed-layer-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transformed-layer-expected.txt
index 6ed89ba..b336d739 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transformed-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transformed-layer-expected.txt
@@ -9,21 +9,16 @@
     {
       "name": "LayoutBlockFlow DIV id='container'",
       "position": [23, 8],
-      "transformOrigin": [377, 0],
       "bounds": [256, 256],
       "contentsOpaque": true,
       "drawsContent": true,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [-10, 0, 0, 1]
-      ]
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='composited'",
-      "position": [385, 0],
-      "contentsOpaque": true
+      "position": [408, 8],
+      "contentsOpaque": true,
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='green'",
@@ -32,6 +27,17 @@
       "drawsContent": true,
       "backgroundColor": "#008000"
     }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [-10, 0, 0, 1]
+      ]
+    }
   ]
 }
 
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transformed-layer-with-transform-body-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transformed-layer-with-transform-body-expected.txt
index 1c0ee4a45..d5aa3d95 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transformed-layer-with-transform-body-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transformed-layer-with-transform-body-expected.txt
@@ -15,28 +15,35 @@
     {
       "name": "LayoutBlockFlow DIV id='container'",
       "position": [15, 0],
-      "transformOrigin": [377, 0],
       "bounds": [256, 256],
       "contentsOpaque": true,
       "drawsContent": true,
+      "transform": 1
+    },
+    {
+      "name": "LayoutBlockFlow (positioned) DIV id='composited'",
+      "position": [400, 0],
+      "contentsOpaque": true,
+      "transform": 1
+    },
+    {
+      "name": "LayoutBlockFlow (positioned) DIV id='green'",
+      "position": [8, 8],
+      "bounds": [300, 300],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "backgroundColor": "#008000"
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
         [-10, 0, 0, 1]
       ]
-    },
-    {
-      "name": "LayoutBlockFlow (positioned) DIV id='composited'",
-      "position": [385, 0],
-      "contentsOpaque": true
-    },
-    {
-      "name": "LayoutBlockFlow (positioned) DIV id='green'",
-      "bounds": [300, 300],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "backgroundColor": "#008000"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transformed-preserved-3d-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transformed-preserved-3d-expected.txt
index 367e634..1243019 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transformed-preserved-3d-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transformed-preserved-3d-expected.txt
@@ -14,105 +14,151 @@
     },
     {
       "name": "Child Transform Layer",
-      "transformOrigin": [50, 50],
-      "shouldFlattenTransform": false,
+      "transform": 1
+    },
+    {
+      "name": "LayoutBlockFlow DIV id='camera' class='rotate-3d-start'",
+      "contentsOpaque": true,
+      "transform": 2
+    },
+    {
+      "name": "LayoutBlockFlow (positioned) DIV class='side side-1'",
+      "bounds": [100, 100],
+      "drawsContent": true,
+      "backgroundColor": "#00FF00CC",
+      "transform": 3
+    },
+    {
+      "name": "LayoutBlockFlow (positioned) DIV class='side side-2'",
+      "bounds": [100, 100],
+      "drawsContent": true,
+      "backgroundColor": "#00FF00CC",
+      "transform": 4
+    },
+    {
+      "name": "LayoutBlockFlow (positioned) DIV class='side side-3'",
+      "bounds": [100, 100],
+      "drawsContent": true,
+      "backgroundColor": "#00FF00CC",
+      "transform": 5
+    },
+    {
+      "name": "LayoutBlockFlow (positioned) DIV class='side side-4'",
+      "bounds": [100, 100],
+      "drawsContent": true,
+      "backgroundColor": "#00FF00CC",
+      "transform": 6
+    },
+    {
+      "name": "LayoutBlockFlow (positioned) DIV class='side side-5'",
+      "bounds": [100, 100],
+      "drawsContent": true,
+      "backgroundColor": "#00FF00CC",
+      "transform": 7
+    },
+    {
+      "name": "LayoutBlockFlow (positioned) DIV class='side side-6'",
+      "bounds": [100, 100],
+      "drawsContent": true,
+      "backgroundColor": "#00FF00CC",
+      "transform": 8
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, -0.005],
         [0, 0, 0, 1]
-      ]
+      ],
+      "origin": [50, 50],
+      "flattenInheritedTransform": false
     },
     {
-      "name": "LayoutBlockFlow DIV id='camera' class='rotate-3d-start'",
-      "transformOrigin": [50, 50],
-      "contentsOpaque": true,
-      "shouldFlattenTransform": false,
-      "3dRenderingContext": 1,
+      "id": 2,
+      "parent": 1,
       "transform": [
         [0.353553390593274, 0.25, -0.5, 0],
         [0, 0.353553390593274, 0.707106781186548, 0],
         [0.353553390593274, -0.25, 0.5, 0],
         [0, 0, 0, 1]
-      ]
+      ],
+      "origin": [50, 50],
+      "flattenInheritedTransform": false,
+      "renderingContext": 1
     },
     {
-      "name": "LayoutBlockFlow (positioned) DIV class='side side-1'",
-      "bounds": [100, 100],
-      "3dRenderingContext": 1,
-      "drawsContent": true,
-      "backgroundColor": "#00FF00CC",
+      "id": 3,
+      "parent": 2,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
         [0, 0, 50, 1]
-      ]
+      ],
+      "renderingContext": 1
     },
     {
-      "name": "LayoutBlockFlow (positioned) DIV class='side side-2'",
-      "bounds": [100, 100],
-      "3dRenderingContext": 1,
-      "drawsContent": true,
-      "backgroundColor": "#00FF00CC",
+      "id": 4,
+      "parent": 2,
       "transform": [
         [0, 0, -1, 0],
         [0, 1, 0, 0],
         [1, 0, 0, 0],
         [50, 0, 0, 1]
-      ]
+      ],
+      "origin": [50, 50],
+      "renderingContext": 1
     },
     {
-      "name": "LayoutBlockFlow (positioned) DIV class='side side-3'",
-      "bounds": [100, 100],
-      "3dRenderingContext": 1,
-      "drawsContent": true,
-      "backgroundColor": "#00FF00CC",
+      "id": 5,
+      "parent": 2,
       "transform": [
         [-1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, -1, 0],
         [0, 0, -50, 1]
-      ]
+      ],
+      "origin": [50, 50],
+      "renderingContext": 1
     },
     {
-      "name": "LayoutBlockFlow (positioned) DIV class='side side-4'",
-      "bounds": [100, 100],
-      "3dRenderingContext": 1,
-      "drawsContent": true,
-      "backgroundColor": "#00FF00CC",
+      "id": 6,
+      "parent": 2,
       "transform": [
         [0, 0, 1, 0],
         [0, 1, 0, 0],
         [-1, 0, 0, 0],
         [-50, 0, 0, 1]
-      ]
+      ],
+      "origin": [50, 50],
+      "renderingContext": 1
     },
     {
-      "name": "LayoutBlockFlow (positioned) DIV class='side side-5'",
-      "bounds": [100, 100],
-      "3dRenderingContext": 1,
-      "drawsContent": true,
-      "backgroundColor": "#00FF00CC",
+      "id": 7,
+      "parent": 2,
       "transform": [
         [1, 0, 0, 0],
         [0, 0, 1, 0],
         [0, -1, 0, 0],
         [0, -50, 0, 1]
-      ]
+      ],
+      "origin": [50, 50],
+      "renderingContext": 1
     },
     {
-      "name": "LayoutBlockFlow (positioned) DIV class='side side-6'",
-      "bounds": [100, 100],
-      "3dRenderingContext": 1,
-      "drawsContent": true,
-      "backgroundColor": "#00FF00CC",
+      "id": 8,
+      "parent": 2,
       "transform": [
         [1, 0, 0, 0],
         [0, 0, -1, 0],
         [0, 1, 0, 0],
         [0, 50, 0, 1]
-      ]
+      ],
+      "origin": [50, 50],
+      "renderingContext": 1
     }
   ]
 }
@@ -133,109 +179,57 @@
     },
     {
       "name": "Child Transform Layer",
-      "transformOrigin": [50, 50],
-      "shouldFlattenTransform": false,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, -0.005],
-        [0, 0, 0, 1]
-      ]
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow DIV id='camera' class='rotate-3d-start rotate-3d-end'",
-      "transformOrigin": [50, 50],
       "contentsOpaque": true,
-      "shouldFlattenTransform": false,
-      "3dRenderingContext": 1,
-      "transform": [
-        [0.707106781186548, 0.5, -0.5, 0],
-        [0, 0.707106781186548, 0.707106781186548, 0],
-        [0.707106781186548, -0.5, 0.5, 0],
-        [0, 0, 0, 1]
-      ]
+      "transform": 2
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='side side-1'",
       "bounds": [100, 100],
-      "3dRenderingContext": 1,
       "drawsContent": true,
       "backgroundColor": "#00FF00CC",
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [0, 0, 50, 1]
-      ]
+      "transform": 3
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='side side-2'",
       "bounds": [100, 100],
-      "3dRenderingContext": 1,
       "drawsContent": true,
       "backgroundColor": "#00FF00CC",
-      "transform": [
-        [0, 0, -1, 0],
-        [0, 1, 0, 0],
-        [1, 0, 0, 0],
-        [50, 0, 0, 1]
-      ]
+      "transform": 4
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='side side-3'",
       "bounds": [100, 100],
-      "3dRenderingContext": 1,
       "drawsContent": true,
       "backgroundColor": "#00FF00CC",
-      "transform": [
-        [-1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, -1, 0],
-        [0, 0, -50, 1]
-      ]
+      "transform": 5
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='side side-4'",
       "bounds": [100, 100],
-      "3dRenderingContext": 1,
       "drawsContent": true,
       "backgroundColor": "#00FF00CC",
-      "transform": [
-        [0, 0, 1, 0],
-        [0, 1, 0, 0],
-        [-1, 0, 0, 0],
-        [-50, 0, 0, 1]
-      ]
+      "transform": 6
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='side side-5'",
       "bounds": [100, 100],
-      "3dRenderingContext": 1,
       "drawsContent": true,
       "backgroundColor": "#00FF00CC",
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 0, 1, 0],
-        [0, -1, 0, 0],
-        [0, -50, 0, 1]
-      ]
+      "transform": 7
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='side side-6'",
       "bounds": [100, 100],
-      "3dRenderingContext": 1,
       "drawsContent": true,
       "backgroundColor": "#00FF00CC",
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 0, -1, 0],
-        [0, 1, 0, 0],
-        [0, 50, 0, 1]
-      ]
+      "transform": 8
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='box top left'",
@@ -251,6 +245,103 @@
       "bounds": [300, 300],
       "drawsContent": true
     }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, -0.005],
+        [0, 0, 0, 1]
+      ],
+      "origin": [50, 50],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [0.707106781186548, 0.5, -0.5, 0],
+        [0, 0.707106781186548, 0.707106781186548, 0],
+        [0.707106781186548, -0.5, 0.5, 0],
+        [0, 0, 0, 1]
+      ],
+      "origin": [50, 50],
+      "flattenInheritedTransform": false,
+      "renderingContext": 1
+    },
+    {
+      "id": 3,
+      "parent": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, 50, 1]
+      ],
+      "renderingContext": 1
+    },
+    {
+      "id": 4,
+      "parent": 2,
+      "transform": [
+        [0, 0, -1, 0],
+        [0, 1, 0, 0],
+        [1, 0, 0, 0],
+        [50, 0, 0, 1]
+      ],
+      "origin": [50, 50],
+      "renderingContext": 1
+    },
+    {
+      "id": 5,
+      "parent": 2,
+      "transform": [
+        [-1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, -1, 0],
+        [0, 0, -50, 1]
+      ],
+      "origin": [50, 50],
+      "renderingContext": 1
+    },
+    {
+      "id": 6,
+      "parent": 2,
+      "transform": [
+        [0, 0, 1, 0],
+        [0, 1, 0, 0],
+        [-1, 0, 0, 0],
+        [-50, 0, 0, 1]
+      ],
+      "origin": [50, 50],
+      "renderingContext": 1
+    },
+    {
+      "id": 7,
+      "parent": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 0, 1, 0],
+        [0, -1, 0, 0],
+        [0, -50, 0, 1]
+      ],
+      "origin": [50, 50],
+      "renderingContext": 1
+    },
+    {
+      "id": 8,
+      "parent": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 0, -1, 0],
+        [0, 1, 0, 0],
+        [0, 50, 0, 1]
+      ],
+      "origin": [50, 50],
+      "renderingContext": 1
+    }
   ]
 }
 
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transforms-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transforms-expected.txt
index b71c25e..b831be21 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transforms-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transforms-expected.txt
@@ -14,7 +14,7 @@
     },
     {
       "name": "Child Containment Layer",
-      "position": [1, 1],
+      "position": [9, 9],
       "bounds": [120, 240]
     },
     {
@@ -24,6 +24,12 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#0000FF",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/rotate3d-overlap-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/rotate3d-overlap-expected.txt
index bbf325b8..06a14467 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/rotate3d-overlap-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/rotate3d-overlap-expected.txt
@@ -16,8 +16,7 @@
       "backgroundColor": "#0000FF"
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='composited box rotate15'",
@@ -25,12 +24,7 @@
       "bounds": [110, 110],
       "drawsContent": true,
       "backgroundColor": "#0000FF",
-      "transform": [
-        [0.965925826289068, 0.258819045102521, 0, 0],
-        [-0.258819045102521, 0.965925826289068, 0, 0],
-        [0, 0, 1, 0],
-        [0, 0, 0, 1]
-      ]
+      "transform": 1
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (relative positioned) DIV class='box')",
@@ -39,8 +33,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='composited box rotate45'",
@@ -48,12 +41,7 @@
       "bounds": [110, 110],
       "drawsContent": true,
       "backgroundColor": "#0000FF",
-      "transform": [
-        [0.707106781186548, 0.707106781186548, 0, 0],
-        [-0.707106781186548, 0.707106781186548, 0, 0],
-        [0, 0, 1, 0],
-        [0, 0, 0, 1]
-      ]
+      "transform": 2
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (relative positioned) DIV class='box')",
@@ -61,6 +49,28 @@
       "bounds": [110, 110],
       "drawsContent": true
     }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [0.965925826289068, 0.258819045102521, 0, 0],
+        [-0.258819045102521, 0.965925826289068, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, 0, 1]
+      ],
+      "origin": [55, 55]
+    },
+    {
+      "id": 2,
+      "transform": [
+        [0.707106781186548, 0.707106781186548, 0, 0],
+        [-0.707106781186548, 0.707106781186548, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, 0, 1]
+      ],
+      "origin": [55, 55]
+    }
   ]
 }
 
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/scroll-partial-update-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/scroll-partial-update-expected.txt
index 76dbf031..49a29b81 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/scroll-partial-update-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/scroll-partial-update-expected.txt
@@ -8,8 +8,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow DIV id='composited'",
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/spanOverlapsCanvas-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/spanOverlapsCanvas-expected.txt
index 8fdee5e..626336b 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/spanOverlapsCanvas-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/spanOverlapsCanvas-expected.txt
@@ -7,8 +7,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutHTMLCanvas CANVAS id='world'",
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/squashing-into-ancestor-clipping-layer-change-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/squashing-into-ancestor-clipping-layer-change-expected.txt
index cef824b..1fd543e5 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/squashing-into-ancestor-clipping-layer-change-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/squashing-into-ancestor-clipping-layer-change-expected.txt
@@ -9,12 +9,11 @@
     {
       "name": "Ancestor Clipping Layer",
       "position": [8, 8],
-      "bounds": [100, 100],
-      "shouldFlattenTransform": false
+      "bounds": [100, 100]
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='composited'",
-      "position": [0, 50],
+      "position": [8, 58],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -22,7 +21,7 @@
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (relative positioned) DIV id='squashed')",
-      "position": [0, 50],
+      "position": [8, 58],
       "bounds": [100, 100],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/stacking-context-overlap-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/stacking-context-overlap-expected.txt
index 5f57e8c..3cf5a09 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/stacking-context-overlap-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/stacking-context-overlap-expected.txt
@@ -7,8 +7,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow DIV class='trigger'",
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/stacking-context-overlap-nested-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/stacking-context-overlap-nested-expected.txt
index 890283d..17b8580 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/stacking-context-overlap-nested-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/stacking-context-overlap-nested-expected.txt
@@ -15,7 +15,7 @@
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited box'",
-      "position": [50, 50],
+      "position": [60, 60],
       "bounds": [220, 120],
       "drawsContent": true,
       "backgroundColor": "#FF000099"
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/accelerated-overflow-scroll-should-not-affect-perspective-expected.txt b/third_party/WebKit/LayoutTests/compositing/overflow/accelerated-overflow-scroll-should-not-affect-perspective-expected.txt
index 854ee12e..c197f1c 100644
--- a/third_party/WebKit/LayoutTests/compositing/overflow/accelerated-overflow-scroll-should-not-affect-perspective-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/accelerated-overflow-scroll-should-not-affect-perspective-expected.txt
@@ -10,29 +10,22 @@
       "name": "LayoutBlockFlow (positioned) DIV class='container'",
       "position": [8, 8],
       "bounds": [200, 200],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Child Transform Layer",
       "bounds": [200, 200],
-      "shouldFlattenTransform": false,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, -0.01],
-        [0, 0, 0, 1]
-      ]
+      "transform": 1
     },
     {
       "name": "Scrolling Layer",
       "bounds": [185, 185],
-      "shouldFlattenTransform": false
+      "transform": 1
     },
     {
       "name": "Scrolling Contents Layer",
       "bounds": [185, 290],
-      "shouldFlattenTransform": false
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='child first'",
@@ -41,12 +34,7 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#008000",
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [0, 0, 10, 1]
-      ]
+      "transform": 2
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='child second'",
@@ -55,32 +43,61 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#0000FF",
+      "transform": 3
+    },
+    {
+      "name": "Overflow Controls Host Layer",
+      "position": [8, 8],
+      "bounds": [200, 200]
+    },
+    {
+      "name": "Horizontal Scrollbar Layer",
+      "position": [8, 193],
+      "bounds": [185, 15]
+    },
+    {
+      "name": "Vertical Scrollbar Layer",
+      "position": [193, 8],
+      "bounds": [15, 185]
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [193, 193],
+      "bounds": [15, 15],
+      "drawsContent": true
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, -0.01],
+        [0, 0, 0, 1]
+      ],
+      "origin": [100, 100],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, 10, 1]
+      ]
+    },
+    {
+      "id": 3,
+      "parent": 1,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
         [0, 0, 20, 1]
       ]
-    },
-    {
-      "name": "Overflow Controls Host Layer",
-      "bounds": [200, 200]
-    },
-    {
-      "name": "Horizontal Scrollbar Layer",
-      "position": [0, 185],
-      "bounds": [185, 15]
-    },
-    {
-      "name": "Vertical Scrollbar Layer",
-      "position": [185, 0],
-      "bounds": [15, 185]
-    },
-    {
-      "name": "Scroll Corner Layer",
-      "position": [185, 185],
-      "bounds": [15, 15],
-      "drawsContent": true
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/clear-scroll-parent-expected.txt b/third_party/WebKit/LayoutTests/compositing/overflow/clear-scroll-parent-expected.txt
index 86a7938..445cdfbc 100644
--- a/third_party/WebKit/LayoutTests/compositing/overflow/clear-scroll-parent-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/clear-scroll-parent-expected.txt
@@ -10,33 +10,33 @@
       "name": "LayoutBlockFlow DIV class='container'",
       "position": [8, 8],
       "bounds": [308, 208],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#00FF0080"
     },
     {
       "name": "Scrolling Layer",
-      "position": [4, 4],
-      "bounds": [285, 200],
-      "shouldFlattenTransform": false
+      "position": [12, 12],
+      "bounds": [285, 200]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [12, 12],
       "bounds": [285, 530],
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 8],
       "bounds": [308, 208]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [289, 4],
+      "position": [297, 12],
       "bounds": [15, 185]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [289, 189],
+      "position": [297, 197],
       "bounds": [15, 15],
       "drawsContent": true
     },
@@ -52,19 +52,17 @@
       "name": "Ancestor Clipping Layer",
       "position": [12, 12],
       "bounds": [80, 80],
-      "shouldFlattenTransform": false,
       "hasScrollParent": true
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='box red'",
-      "position": [10, 10],
+      "position": [22, 22],
       "bounds": [100, 100],
       "drawsContent": true,
       "backgroundColor": "#FF000080"
     },
     {
       "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false,
       "hasScrollParent": true
     },
     {
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/clip-descendents-expected.txt b/third_party/WebKit/LayoutTests/compositing/overflow/clip-descendents-expected.txt
index 995a3ddf..4d1409d 100644
--- a/third_party/WebKit/LayoutTests/compositing/overflow/clip-descendents-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/clip-descendents-expected.txt
@@ -9,8 +9,7 @@
     {
       "name": "Ancestor Clipping Layer",
       "position": [48, 38],
-      "bounds": [60, 70],
-      "shouldFlattenTransform": false
+      "bounds": [60, 70]
     },
     {
       "name": "LayoutBlockFlow DIV class='box'",
@@ -19,18 +18,12 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#808080",
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [0, 0, 1, 1]
-      ]
+      "transform": 1
     },
     {
       "name": "Ancestor Clipping Layer",
       "position": [240, 38],
-      "bounds": [60, 70],
-      "shouldFlattenTransform": false
+      "bounds": [60, 70]
     },
     {
       "name": "LayoutBlockFlow DIV class='box'",
@@ -39,12 +32,7 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#808080",
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [0, 0, 1, 1]
-      ]
+      "transform": 2
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='container'",
@@ -54,6 +42,7 @@
     },
     {
       "name": "Child Containment Layer",
+      "position": [48, 230],
       "bounds": [60, 70]
     },
     {
@@ -63,12 +52,7 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#808080",
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [0, 0, 1, 1]
-      ]
+      "transform": 3
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='container'",
@@ -78,6 +62,7 @@
     },
     {
       "name": "Child Containment Layer",
+      "position": [240, 230],
       "bounds": [60, 70]
     },
     {
@@ -87,6 +72,39 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#808080",
+      "transform": 4
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, 1, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, 1, 1]
+      ]
+    },
+    {
+      "id": 3,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, 1, 1]
+      ]
+    },
+    {
+      "id": 4,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/composited-scrolling-paint-phases-expected.txt b/third_party/WebKit/LayoutTests/compositing/overflow/composited-scrolling-paint-phases-expected.txt
index 530bce2..24541e10 100644
--- a/third_party/WebKit/LayoutTests/compositing/overflow/composited-scrolling-paint-phases-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/composited-scrolling-paint-phases-expected.txt
@@ -47,7 +47,6 @@
       "name": "LayoutBlockFlow DIV class='container'",
       "position": [28, 20],
       "bounds": [202, 202],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "paintingPhases": [
         "GraphicsLayerPaintBackground",
@@ -58,9 +57,8 @@
     },
     {
       "name": "Scrolling Layer",
-      "position": [1, 1],
+      "position": [29, 21],
       "bounds": [185, 185],
-      "shouldFlattenTransform": false,
       "paintingPhases": [
         "GraphicsLayerPaintBackground",
         "GraphicsLayerPaintForeground",
@@ -70,6 +68,7 @@
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [29, 21],
       "bounds": [185, 715],
       "drawsContent": true,
       "paintingPhases": [
@@ -80,6 +79,7 @@
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [28, 20],
       "bounds": [202, 202],
       "paintingPhases": [
         "GraphicsLayerPaintBackground",
@@ -90,7 +90,7 @@
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [1, 186],
+      "position": [29, 206],
       "bounds": [185, 15],
       "paintingPhases": [
         "GraphicsLayerPaintBackground",
@@ -101,7 +101,7 @@
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [186, 1],
+      "position": [214, 21],
       "bounds": [15, 185],
       "paintingPhases": [
         "GraphicsLayerPaintBackground",
@@ -112,7 +112,7 @@
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [186, 186],
+      "position": [214, 206],
       "bounds": [15, 15],
       "drawsContent": true,
       "paintingPhases": [
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/content-gains-scrollbars-expected.txt b/third_party/WebKit/LayoutTests/compositing/overflow/content-gains-scrollbars-expected.txt
index e798453..a3908c3 100644
--- a/third_party/WebKit/LayoutTests/compositing/overflow/content-gains-scrollbars-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/content-gains-scrollbars-expected.txt
@@ -10,97 +10,103 @@
       "name": "LayoutBlockFlow (positioned) DIV class='container'",
       "position": [8, 13],
       "bounds": [100, 100],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [85, 100],
-      "shouldFlattenTransform": false
+      "position": [8, 13],
+      "bounds": [85, 100]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 13],
       "bounds": [85, 200]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='vertical' class='content tall'",
+      "position": [8, 13],
       "bounds": [10, 200]
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 13],
       "bounds": [100, 100]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [85, 0],
+      "position": [93, 13],
       "bounds": [15, 100]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='container'",
       "position": [8, 13],
       "bounds": [100, 100],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [100, 85],
-      "shouldFlattenTransform": false
+      "position": [8, 13],
+      "bounds": [100, 85]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 13],
       "bounds": [200, 85]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='horizontal' class='content wide'",
+      "position": [8, 13],
       "bounds": [200, 10]
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 13],
       "bounds": [100, 100]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [0, 85],
+      "position": [8, 98],
       "bounds": [100, 15]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='container'",
       "position": [8, 13],
       "bounds": [100, 100],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [85, 85],
-      "shouldFlattenTransform": false
+      "position": [8, 13],
+      "bounds": [85, 85]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 13],
       "bounds": [200, 200]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='both' class='content wide tall'",
+      "position": [8, 13],
       "bounds": [200, 200]
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 13],
       "bounds": [100, 100]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [0, 85],
+      "position": [8, 98],
       "bounds": [85, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [85, 0],
+      "position": [93, 13],
       "bounds": [15, 85]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [85, 85],
+      "position": [93, 98],
       "bounds": [15, 15],
       "drawsContent": true
     },
@@ -112,19 +118,22 @@
     },
     {
       "name": "Child Containment Layer",
+      "position": [8, 13],
       "bounds": [100, 100]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='content'",
+      "position": [8, 13],
       "bounds": [10, 10]
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 13],
       "bounds": [100, 100]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [85, 85],
+      "position": [93, 98],
       "bounds": [15, 15],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/content-loses-scrollbars-expected.txt b/third_party/WebKit/LayoutTests/compositing/overflow/content-loses-scrollbars-expected.txt
index 8d230d3..479ea19 100644
--- a/third_party/WebKit/LayoutTests/compositing/overflow/content-loses-scrollbars-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/content-loses-scrollbars-expected.txt
@@ -13,10 +13,12 @@
     },
     {
       "name": "Child Containment Layer",
+      "position": [8, 13],
       "bounds": [100, 100]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='vertical' class='content'",
+      "position": [8, 13],
       "bounds": [10, 10]
     },
     {
@@ -26,10 +28,12 @@
     },
     {
       "name": "Child Containment Layer",
+      "position": [8, 13],
       "bounds": [100, 100]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='horizontal' class='content'",
+      "position": [8, 13],
       "bounds": [10, 10]
     },
     {
@@ -39,10 +43,12 @@
     },
     {
       "name": "Child Containment Layer",
+      "position": [8, 13],
       "bounds": [100, 100]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='both' class='content'",
+      "position": [8, 13],
       "bounds": [10, 10]
     },
     {
@@ -52,10 +58,12 @@
     },
     {
       "name": "Child Containment Layer",
+      "position": [8, 13],
       "bounds": [100, 100]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='content'",
+      "position": [8, 13],
       "bounds": [10, 10]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/no-excessive-clip-parent-if-parent-escaped-expected.txt b/third_party/WebKit/LayoutTests/compositing/overflow/no-excessive-clip-parent-if-parent-escaped-expected.txt
index 85819e0..f7c3bae 100644
--- a/third_party/WebKit/LayoutTests/compositing/overflow/no-excessive-clip-parent-if-parent-escaped-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/no-excessive-clip-parent-if-parent-escaped-expected.txt
@@ -16,10 +16,12 @@
     },
     {
       "name": "Child Containment Layer",
+      "position": [8, 8],
       "bounds": [100, 100]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV",
+      "position": [8, 8],
       "bounds": [50, 50],
       "contentsOpaque": true,
       "drawsContent": true,
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scrollbar-layers-expected.txt b/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scrollbar-layers-expected.txt
index 417a0ce..aa2b0d5 100644
--- a/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scrollbar-layers-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scrollbar-layers-expected.txt
@@ -10,97 +10,103 @@
       "name": "LayoutBlockFlow (positioned) DIV class='container'",
       "position": [8, 13],
       "bounds": [100, 100],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [85, 100],
-      "shouldFlattenTransform": false
+      "position": [8, 13],
+      "bounds": [85, 100]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 13],
       "bounds": [85, 200]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='content tall'",
+      "position": [8, 13],
       "bounds": [10, 200]
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 13],
       "bounds": [100, 100]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [85, 0],
+      "position": [93, 13],
       "bounds": [15, 100]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='container'",
       "position": [8, 13],
       "bounds": [100, 100],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [100, 85],
-      "shouldFlattenTransform": false
+      "position": [8, 13],
+      "bounds": [100, 85]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 13],
       "bounds": [200, 85]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='content wide'",
+      "position": [8, 13],
       "bounds": [200, 10]
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 13],
       "bounds": [100, 100]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [0, 85],
+      "position": [8, 98],
       "bounds": [100, 15]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='container'",
       "position": [8, 13],
       "bounds": [100, 100],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [85, 85],
-      "shouldFlattenTransform": false
+      "position": [8, 13],
+      "bounds": [85, 85]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 13],
       "bounds": [200, 200]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='content wide tall'",
+      "position": [8, 13],
       "bounds": [200, 200]
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 13],
       "bounds": [100, 100]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [0, 85],
+      "position": [8, 98],
       "bounds": [85, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [85, 0],
+      "position": [93, 13],
       "bounds": [15, 85]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [85, 85],
+      "position": [93, 98],
       "bounds": [15, 15],
       "drawsContent": true
     },
@@ -112,19 +118,22 @@
     },
     {
       "name": "Child Containment Layer",
+      "position": [8, 13],
       "bounds": [100, 100]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='content'",
+      "position": [8, 13],
       "bounds": [10, 10]
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 13],
       "bounds": [100, 100]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [85, 85],
+      "position": [93, 98],
       "bounds": [15, 15],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/reparented-scrollbars-non-sc-anc-expected.txt b/third_party/WebKit/LayoutTests/compositing/overflow/reparented-scrollbars-non-sc-anc-expected.txt
index d178fd3..ce8c20e 100644
--- a/third_party/WebKit/LayoutTests/compositing/overflow/reparented-scrollbars-non-sc-anc-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/reparented-scrollbars-non-sc-anc-expected.txt
@@ -9,36 +9,38 @@
     {
       "name": "Ancestor Clipping Layer",
       "position": [8, 8],
-      "bounds": [1200, 800],
-      "shouldFlattenTransform": false
+      "bounds": [1200, 800]
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='positioned'",
+      "position": [8, 8],
       "bounds": [1200, 800],
       "drawsContent": true
     },
     {
       "name": "Child Containment Layer",
+      "position": [8, 8],
       "bounds": [1200, 800]
     },
     {
       "name": "Ancestor Clipping Layer",
-      "bounds": [1200, 1000],
-      "shouldFlattenTransform": false
+      "position": [8, 8],
+      "bounds": [1200, 1000]
     },
     {
       "name": "LayoutBlockFlow DIV id='scroller'",
+      "position": [8, 8],
       "bounds": [1200, 1000],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [1200, 1000],
-      "shouldFlattenTransform": false
+      "position": [8, 8],
+      "bounds": [1200, 1000]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 8],
       "bounds": [1200, 10000],
       "drawsContent": true
     },
@@ -54,11 +56,12 @@
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 8],
       "bounds": [1200, 1000]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [1193, 0],
+      "position": [1201, 8],
       "bounds": [7, 1000]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/resize-painting-expected.txt b/third_party/WebKit/LayoutTests/compositing/overflow/resize-painting-expected.txt
index 7a929ee0..d7b0088d0 100644
--- a/third_party/WebKit/LayoutTests/compositing/overflow/resize-painting-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/resize-painting-expected.txt
@@ -14,11 +14,12 @@
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [18, 10],
       "bounds": [100, 100]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [85, 85],
+      "position": [103, 95],
       "bounds": [15, 15],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/scroll-parent-absolute-expected.txt b/third_party/WebKit/LayoutTests/compositing/overflow/scroll-parent-absolute-expected.txt
index 710d0933..c0ca36e 100644
--- a/third_party/WebKit/LayoutTests/compositing/overflow/scroll-parent-absolute-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/scroll-parent-absolute-expected.txt
@@ -7,45 +7,45 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow DIV id='top'",
       "position": [8, 8],
       "bounds": [500, 500],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#0000FF"
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [485, 485],
-      "shouldFlattenTransform": false
+      "position": [8, 8],
+      "bounds": [485, 485]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 8],
       "bounds": [485, 5000],
       "contentsOpaque": true,
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 8],
       "bounds": [500, 500]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [0, 485],
+      "position": [8, 493],
       "bounds": [485, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [485, 0],
+      "position": [493, 8],
       "bounds": [15, 485]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [485, 485],
+      "position": [493, 493],
       "bounds": [15, 15],
       "drawsContent": true
     },
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/scroll-parent-absolute-with-backdrop-filter-expected.txt b/third_party/WebKit/LayoutTests/compositing/overflow/scroll-parent-absolute-with-backdrop-filter-expected.txt
index 9a67aee..b5a1464 100644
--- a/third_party/WebKit/LayoutTests/compositing/overflow/scroll-parent-absolute-with-backdrop-filter-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/scroll-parent-absolute-with-backdrop-filter-expected.txt
@@ -10,21 +10,22 @@
       "name": "LayoutBlockFlow DIV id='top'",
       "position": [8, 8],
       "bounds": [500, 500],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [485, 485],
-      "shouldFlattenTransform": false
+      "position": [8, 8],
+      "bounds": [485, 485]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 8],
       "bounds": [485, 5000],
       "drawsContent": true
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='middle'",
+      "position": [8, 8],
       "bounds": [400, 400],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -33,6 +34,7 @@
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='child'",
+      "position": [8, 8],
       "bounds": [300, 300],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -42,6 +44,7 @@
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='tall'",
+      "position": [8, 8],
       "bounds": [20, 5000],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -49,21 +52,22 @@
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 8],
       "bounds": [500, 500]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [0, 485],
+      "position": [8, 493],
       "bounds": [485, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [485, 0],
+      "position": [493, 8],
       "bounds": [15, 485]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [485, 485],
+      "position": [493, 493],
       "bounds": [15, 15],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/scroll-parent-with-non-stacking-context-composited-ancestor-expected.txt b/third_party/WebKit/LayoutTests/compositing/overflow/scroll-parent-with-non-stacking-context-composited-ancestor-expected.txt
index 9bbae17c..73f595f3 100644
--- a/third_party/WebKit/LayoutTests/compositing/overflow/scroll-parent-with-non-stacking-context-composited-ancestor-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/scroll-parent-with-non-stacking-context-composited-ancestor-expected.txt
@@ -17,18 +17,18 @@
     },
     {
       "name": "LayoutBlockFlow DIV id='scroller'",
+      "position": [98, 90],
       "bounds": [102, 102],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "position": [1, 1],
-      "bounds": [100, 100],
-      "shouldFlattenTransform": false
+      "position": [99, 91],
+      "bounds": [100, 100]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [99, 91],
       "bounds": [100, 180]
     },
     {
@@ -40,8 +40,7 @@
       "backgroundColor": "#008000"
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='scrolled'",
@@ -64,7 +63,7 @@
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [94, 1],
+      "position": [192, 91],
       "bounds": [7, 100]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/scrollbar-layer-placement-expected.txt b/third_party/WebKit/LayoutTests/compositing/overflow/scrollbar-layer-placement-expected.txt
index cd12323f..5deec6e26 100644
--- a/third_party/WebKit/LayoutTests/compositing/overflow/scrollbar-layer-placement-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/scrollbar-layer-placement-expected.txt
@@ -14,31 +14,30 @@
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='scroller'",
-      "position": [32, 32],
+      "position": [38, 38],
       "bounds": [278, 218],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#FFFFFF"
     },
     {
       "name": "Scrolling Layer",
-      "position": [29, 29],
-      "bounds": [220, 160],
-      "shouldFlattenTransform": false
+      "position": [67, 67],
+      "bounds": [220, 160]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [67, 67],
       "bounds": [220, 236],
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
-      "position": [24, 24],
+      "position": [62, 62],
       "bounds": [230, 170]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [218, 5],
+      "position": [280, 67],
       "bounds": [7, 160]
     },
     {
@@ -49,26 +48,25 @@
     },
     {
       "name": "LayoutBlockFlow DIV class='scroller'",
-      "position": [32, 32],
+      "position": [387, 38],
       "bounds": [278, 218],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#FFFFFF"
     },
     {
       "name": "Scrolling Layer",
-      "position": [29, 29],
-      "bounds": [220, 160],
-      "shouldFlattenTransform": false
+      "position": [416, 67],
+      "bounds": [220, 160]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [416, 67],
       "bounds": [220, 236],
       "drawsContent": true
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='content'",
-      "position": [73, 73],
+      "position": [428, 79],
       "bounds": [196, 212],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -76,12 +74,12 @@
     },
     {
       "name": "Overflow Controls Host Layer",
-      "position": [56, 56],
+      "position": [411, 62],
       "bounds": [230, 170]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [218, 5],
+      "position": [629, 67],
       "bounds": [7, 160]
     },
     {
@@ -92,32 +90,30 @@
     },
     {
       "name": "Ancestor Clipping Layer",
-      "position": [40, 40],
-      "bounds": [260, 100],
-      "shouldFlattenTransform": false
+      "position": [46, 337],
+      "bounds": [260, 100]
     },
     {
       "name": "LayoutBlockFlow DIV class='scroller'",
-      "position": [-9, -9],
+      "position": [37, 328],
       "bounds": [278, 218],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#FFFFFF"
     },
     {
       "name": "Scrolling Layer",
-      "position": [29, 29],
-      "bounds": [220, 160],
-      "shouldFlattenTransform": false
+      "position": [66, 357],
+      "bounds": [220, 160]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [66, 357],
       "bounds": [220, 236],
       "drawsContent": true
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='content'",
-      "position": [72, 72],
+      "position": [78, 369],
       "bounds": [196, 212],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -125,17 +121,17 @@
     },
     {
       "name": "Overflow Controls Ancestor Clipping Layer",
-      "position": [40, 40],
+      "position": [46, 337],
       "bounds": [260, 100]
     },
     {
       "name": "Overflow Controls Host Layer",
-      "position": [15, 15],
+      "position": [61, 352],
       "bounds": [230, 170]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [218, 5],
+      "position": [279, 357],
       "bounds": [7, 160]
     },
     {
@@ -146,43 +142,41 @@
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='clipper'",
-      "position": [24, 24],
+      "position": [379, 321],
       "bounds": [292, 200],
       "drawsContent": true
     },
     {
       "name": "Child Containment Layer",
-      "position": [10, 10],
+      "position": [389, 331],
       "bounds": [272, 180]
     },
     {
       "name": "Ancestor Clipping Layer",
-      "position": [6, 6],
-      "bounds": [260, 100],
-      "shouldFlattenTransform": false
+      "position": [395, 337],
+      "bounds": [260, 100]
     },
     {
       "name": "LayoutBlockFlow DIV class='scroller'",
-      "position": [-9, -9],
+      "position": [386, 328],
       "bounds": [278, 218],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#FFFFFF"
     },
     {
       "name": "Scrolling Layer",
-      "position": [29, 29],
-      "bounds": [220, 160],
-      "shouldFlattenTransform": false
+      "position": [415, 357],
+      "bounds": [220, 160]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [415, 357],
       "bounds": [220, 236],
       "drawsContent": true
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='content'",
-      "position": [72, 72],
+      "position": [427, 369],
       "bounds": [196, 212],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -190,17 +184,17 @@
     },
     {
       "name": "Overflow Controls Ancestor Clipping Layer",
-      "position": [40, 40],
+      "position": [395, 337],
       "bounds": [260, 100]
     },
     {
       "name": "Overflow Controls Host Layer",
-      "position": [15, 15],
+      "position": [410, 352],
       "bounds": [230, 170]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [218, 5],
+      "position": [628, 357],
       "bounds": [7, 160]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/scrolling-content-clip-to-viewport-expected.txt b/third_party/WebKit/LayoutTests/compositing/overflow/scrolling-content-clip-to-viewport-expected.txt
index c1c3c456..c5feec6 100644
--- a/third_party/WebKit/LayoutTests/compositing/overflow/scrolling-content-clip-to-viewport-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/scrolling-content-clip-to-viewport-expected.txt
@@ -9,13 +9,11 @@
     {
       "name": "LayoutBlockFlow DIV class='scroller'",
       "bounds": [320, 340],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [305, 325],
-      "shouldFlattenTransform": false
+      "bounds": [305, 325]
     },
     {
       "name": "Scrolling Contents Layer",
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/universal-accelerated-overflow-scroll-expected.txt b/third_party/WebKit/LayoutTests/compositing/overflow/universal-accelerated-overflow-scroll-expected.txt
index 150127f9..b5745fc 100644
--- a/third_party/WebKit/LayoutTests/compositing/overflow/universal-accelerated-overflow-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/universal-accelerated-overflow-scroll-expected.txt
@@ -7,44 +7,43 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow DIV id='container-absolute-grandchildren-not-contained' class='overflow'",
       "position": [10, 10],
       "bounds": [104, 104],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "position": [2, 2],
-      "bounds": [85, 85],
-      "shouldFlattenTransform": false
+      "position": [12, 12],
+      "bounds": [85, 85]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [12, 12],
       "bounds": [85, 144],
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [10, 10],
       "bounds": [104, 104]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [2, 87],
+      "position": [12, 97],
       "bounds": [85, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [87, 2],
+      "position": [97, 12],
       "bounds": [15, 85]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [87, 87],
+      "position": [97, 97],
       "bounds": [15, 15],
       "drawsContent": true
     },
@@ -55,8 +54,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-absolute-grandchildren-not-contained' class='scrolled'",
@@ -76,43 +74,42 @@
       "name": "LayoutBlockFlow (positioned) DIV id='container-absolute-grandchildren' class='positionAbsolute overflow'",
       "position": [130, 10],
       "bounds": [104, 104],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "position": [2, 2],
-      "bounds": [85, 85],
-      "shouldFlattenTransform": false
+      "position": [132, 12],
+      "bounds": [85, 85]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [132, 12],
       "bounds": [105, 144],
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [130, 10],
       "bounds": [104, 104]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [2, 87],
+      "position": [132, 97],
       "bounds": [85, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [87, 2],
+      "position": [217, 12],
       "bounds": [15, 85]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [87, 87],
+      "position": [217, 97],
       "bounds": [15, 15],
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='positioned-absolute-grandchildren' class='positionAbsolute positioned'",
@@ -129,43 +126,42 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow DIV id='container-absolute-not-contained' class='overflow'",
       "position": [250, 10],
       "bounds": [104, 104],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "position": [2, 2],
-      "bounds": [85, 85],
-      "shouldFlattenTransform": false
+      "position": [252, 12],
+      "bounds": [85, 85]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [252, 12],
       "bounds": [85, 144]
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [250, 10],
       "bounds": [104, 104]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [2, 87],
+      "position": [252, 97],
       "bounds": [85, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [87, 2],
+      "position": [337, 12],
       "bounds": [15, 85]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [87, 87],
+      "position": [337, 97],
       "bounds": [15, 15],
       "drawsContent": true
     },
@@ -176,8 +172,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-absolute-not-contained' class='scrolled'",
@@ -194,44 +189,43 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow DIV id='container-absolute-sibling-grandchildren-not-contained' class='overflow'",
       "position": [370, 10],
       "bounds": [104, 104],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "position": [2, 2],
-      "bounds": [85, 85],
-      "shouldFlattenTransform": false
+      "position": [372, 12],
+      "bounds": [85, 85]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [372, 12],
       "bounds": [85, 144],
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [370, 10],
       "bounds": [104, 104]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [2, 87],
+      "position": [372, 97],
       "bounds": [85, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [87, 2],
+      "position": [457, 12],
       "bounds": [15, 85]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [87, 87],
+      "position": [457, 97],
       "bounds": [15, 15],
       "drawsContent": true
     },
@@ -242,8 +236,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-absolute-sibling-grandchildren-not-contained' class='scrolled'",
@@ -263,43 +256,42 @@
       "name": "LayoutBlockFlow (positioned) DIV id='container-absolute-sibling-grandchildren' class='positionAbsolute overflow'",
       "position": [10, 130],
       "bounds": [104, 104],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "position": [2, 2],
-      "bounds": [85, 85],
-      "shouldFlattenTransform": false
+      "position": [12, 132],
+      "bounds": [85, 85]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [12, 132],
       "bounds": [105, 144],
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [10, 130],
       "bounds": [104, 104]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [2, 87],
+      "position": [12, 217],
       "bounds": [85, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [87, 2],
+      "position": [97, 132],
       "bounds": [15, 85]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [87, 87],
+      "position": [97, 217],
       "bounds": [15, 15],
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='positioned-absolute-sibling-grandchildren' class='positionAbsolute positioned'",
@@ -316,43 +308,42 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow DIV id='container-absolute-sibling-not-contained' class='overflow'",
       "position": [130, 130],
       "bounds": [104, 104],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "position": [2, 2],
-      "bounds": [85, 85],
-      "shouldFlattenTransform": false
+      "position": [132, 132],
+      "bounds": [85, 85]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [132, 132],
       "bounds": [85, 144]
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [130, 130],
       "bounds": [104, 104]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [2, 87],
+      "position": [132, 217],
       "bounds": [85, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [87, 2],
+      "position": [217, 132],
       "bounds": [15, 85]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [87, 87],
+      "position": [217, 217],
       "bounds": [15, 15],
       "drawsContent": true
     },
@@ -363,8 +354,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-absolute-sibling-not-contained' class='scrolled'",
@@ -384,42 +374,41 @@
       "name": "LayoutBlockFlow (positioned) DIV id='container-absolute-sibling' class='positionAbsolute overflow'",
       "position": [250, 130],
       "bounds": [104, 104],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "position": [2, 2],
-      "bounds": [85, 85],
-      "shouldFlattenTransform": false
+      "position": [252, 132],
+      "bounds": [85, 85]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [252, 132],
       "bounds": [105, 144]
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [250, 130],
       "bounds": [104, 104]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [2, 87],
+      "position": [252, 217],
       "bounds": [85, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [87, 2],
+      "position": [337, 132],
       "bounds": [15, 85]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [87, 87],
+      "position": [337, 217],
       "bounds": [15, 15],
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='positioned-absolute-sibling' class='positionAbsolute positioned'",
@@ -439,42 +428,41 @@
       "name": "LayoutBlockFlow (positioned) DIV id='container-absolute' class='positionAbsolute overflow'",
       "position": [370, 130],
       "bounds": [104, 104],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "position": [2, 2],
-      "bounds": [85, 85],
-      "shouldFlattenTransform": false
+      "position": [372, 132],
+      "bounds": [85, 85]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [372, 132],
       "bounds": [105, 144]
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [370, 130],
       "bounds": [104, 104]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [2, 87],
+      "position": [372, 217],
       "bounds": [85, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [87, 2],
+      "position": [457, 132],
       "bounds": [15, 85]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [87, 87],
+      "position": [457, 217],
       "bounds": [15, 15],
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='positioned-absolute' class='positionAbsolute positioned'",
@@ -494,37 +482,37 @@
       "name": "LayoutBlockFlow (positioned) DIV id='container-fixed-sibling-grandchildren' class='positionAbsolute overflow'",
       "position": [10, 250],
       "bounds": [104, 104],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "position": [2, 2],
-      "bounds": [85, 85],
-      "shouldFlattenTransform": false
+      "position": [12, 252],
+      "bounds": [85, 85]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [12, 252],
       "bounds": [85, 144],
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [10, 250],
       "bounds": [104, 104]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [2, 87],
+      "position": [12, 337],
       "bounds": [85, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [87, 2],
+      "position": [97, 252],
       "bounds": [15, 85]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [87, 87],
+      "position": [97, 337],
       "bounds": [15, 15],
       "drawsContent": true
     },
@@ -537,8 +525,7 @@
       "backgroundColor": "#800080"
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-fixed-sibling-grandchildren' class='scrolled'",
@@ -558,36 +545,36 @@
       "name": "LayoutBlockFlow (positioned) DIV id='container-fixed-sibling' class='positionAbsolute overflow'",
       "position": [130, 250],
       "bounds": [104, 104],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "position": [2, 2],
-      "bounds": [85, 85],
-      "shouldFlattenTransform": false
+      "position": [132, 252],
+      "bounds": [85, 85]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [132, 252],
       "bounds": [85, 144]
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [130, 250],
       "bounds": [104, 104]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [2, 87],
+      "position": [132, 337],
       "bounds": [85, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [87, 2],
+      "position": [217, 252],
       "bounds": [15, 85]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [87, 87],
+      "position": [217, 337],
       "bounds": [15, 15],
       "drawsContent": true
     },
@@ -600,8 +587,7 @@
       "backgroundColor": "#800080"
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-fixed-sibling' class='scrolled'",
@@ -621,37 +607,37 @@
       "name": "LayoutBlockFlow (positioned) DIV id='container-fixed-grandchildren' class='positionAbsolute overflow'",
       "position": [250, 250],
       "bounds": [104, 104],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "position": [2, 2],
-      "bounds": [85, 85],
-      "shouldFlattenTransform": false
+      "position": [252, 252],
+      "bounds": [85, 85]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [252, 252],
       "bounds": [85, 144],
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [250, 250],
       "bounds": [104, 104]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [2, 87],
+      "position": [252, 337],
       "bounds": [85, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [87, 2],
+      "position": [337, 252],
       "bounds": [15, 85]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [87, 87],
+      "position": [337, 337],
       "bounds": [15, 15],
       "drawsContent": true
     },
@@ -664,8 +650,7 @@
       "backgroundColor": "#800080"
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-fixed-grandchildren' class='scrolled'",
@@ -685,36 +670,36 @@
       "name": "LayoutBlockFlow (positioned) DIV id='container-fixed' class='positionAbsolute overflow'",
       "position": [370, 250],
       "bounds": [104, 104],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "position": [2, 2],
-      "bounds": [85, 85],
-      "shouldFlattenTransform": false
+      "position": [372, 252],
+      "bounds": [85, 85]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [372, 252],
       "bounds": [85, 144]
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [370, 250],
       "bounds": [104, 104]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [2, 87],
+      "position": [372, 337],
       "bounds": [85, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [87, 2],
+      "position": [457, 252],
       "bounds": [15, 85]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [87, 87],
+      "position": [457, 337],
       "bounds": [15, 15],
       "drawsContent": true
     },
@@ -727,8 +712,7 @@
       "backgroundColor": "#800080"
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-fixed' class='scrolled'",
@@ -793,8 +777,7 @@
       "backgroundColor": "#008000"
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-absolute-grandchildren-not-contained' class='scrolled onTop'",
@@ -811,8 +794,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-absolute-grandchildren' class='scrolled onTop'",
@@ -829,8 +811,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-absolute-not-contained' class='scrolled onTop'",
@@ -847,8 +828,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-absolute-sibling-grandchildren-not-contained' class='scrolled onTop'",
@@ -865,8 +845,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-absolute-sibling-grandchildren' class='scrolled onTop'",
@@ -883,8 +862,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-absolute-sibling-not-contained' class='scrolled onTop'",
@@ -901,8 +879,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-absolute-sibling' class='scrolled onTop'",
@@ -919,8 +896,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-absolute' class='scrolled onTop'",
@@ -937,8 +913,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-fixed-sibling-grandchildren' class='scrolled onTop'",
@@ -955,8 +930,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-fixed-sibling' class='scrolled onTop'",
@@ -973,8 +947,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-fixed-grandchildren' class='scrolled onTop'",
@@ -991,8 +964,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-fixed' class='scrolled onTop'",
diff --git a/third_party/WebKit/LayoutTests/compositing/rendering-contexts-expected.txt b/third_party/WebKit/LayoutTests/compositing/rendering-contexts-expected.txt
index 4963084..3191c295d 100644
--- a/third_party/WebKit/LayoutTests/compositing/rendering-contexts-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/rendering-contexts-expected.txt
@@ -11,27 +11,43 @@
       "position": [8, 8],
       "bounds": [100, 100],
       "contentsOpaque": true,
-      "shouldFlattenTransform": false,
-      "3dRenderingContext": 1,
       "drawsContent": true,
-      "backgroundColor": "#008000"
+      "backgroundColor": "#008000",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow DIV id='parent' class='composited'",
       "bounds": [100, 100],
       "contentsOpaque": true,
-      "3dRenderingContext": 1,
       "drawsContent": true,
-      "backgroundColor": "#008000"
+      "backgroundColor": "#008000",
+      "transform": 2
     },
     {
       "name": "LayoutBlockFlow DIV id='child' class='composited'",
       "bounds": [100, 100],
       "contentsOpaque": true,
-      "shouldFlattenTransform": false,
-      "3dRenderingContext": 2,
       "drawsContent": true,
-      "backgroundColor": "#008000"
+      "backgroundColor": "#008000",
+      "transform": 3
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "flattenInheritedTransform": false,
+      "renderingContext": 1
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "renderingContext": 1
+    },
+    {
+      "id": 3,
+      "parent": 2,
+      "flattenInheritedTransform": false,
+      "renderingContext": 2
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-expected.txt b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-expected.txt
index 6728ebe2e..9cf7ae13 100644
--- a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-expected.txt
@@ -25,7 +25,6 @@
     },
     {
       "name": "Content Root Layer",
-      "position": [-615, 0],
       "bounds": [1000, 1000]
     },
     {
diff --git a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-scrolled-expected.txt b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-scrolled-expected.txt
index 21e4f50..3494218 100644
--- a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-scrolled-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-scrolled-expected.txt
@@ -25,7 +25,6 @@
     },
     {
       "name": "Content Root Layer",
-      "position": [-615, 0],
       "bounds": [1000, 1000]
     },
     {
diff --git a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-expected.txt b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-expected.txt
index a49dc97..cfb954d5 100644
--- a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-expected.txt
@@ -25,7 +25,6 @@
     },
     {
       "name": "Content Root Layer",
-      "position": [-615, 0],
       "bounds": [1000, 1000]
     },
     {
diff --git a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-scrolled-expected.txt b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-scrolled-expected.txt
index a49dc97..cfb954d5 100644
--- a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-scrolled-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-scrolled-expected.txt
@@ -25,7 +25,6 @@
     },
     {
       "name": "Content Root Layer",
-      "position": [-615, 0],
       "bounds": [1000, 1000]
     },
     {
diff --git a/third_party/WebKit/LayoutTests/compositing/scrollbars/nested-overlay-scrollbars-expected.txt b/third_party/WebKit/LayoutTests/compositing/scrollbars/nested-overlay-scrollbars-expected.txt
index 47d11c63..e05f7a6b 100644
--- a/third_party/WebKit/LayoutTests/compositing/scrollbars/nested-overlay-scrollbars-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/scrollbars/nested-overlay-scrollbars-expected.txt
@@ -10,45 +10,43 @@
       "name": "LayoutBlockFlow (positioned) DIV id='outer'",
       "position": [8, 8],
       "bounds": [404, 404],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "position": [2, 2],
-      "bounds": [400, 400],
-      "shouldFlattenTransform": false
+      "position": [10, 10],
+      "bounds": [400, 400]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [10, 10],
       "bounds": [400, 704],
       "drawsContent": true
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='inner'",
-      "position": [0, 500],
+      "position": [10, 510],
       "bounds": [204, 204],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "position": [2, 2],
-      "bounds": [200, 200],
-      "shouldFlattenTransform": false
+      "position": [12, 512],
+      "bounds": [200, 200]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [12, 512],
       "bounds": [5000, 9000],
       "drawsContent": true
     },
     {
       "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "position": [10, 10]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='grey'",
-      "position": [2, 502],
+      "position": [12, 512],
       "bounds": [100, 800],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -56,38 +54,39 @@
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (positioned) DIV id='spacer')",
-      "position": [2, 2502],
+      "position": [12, 2512],
       "bounds": [5000, 1000],
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
-      "position": [2, 502],
+      "position": [12, 512],
       "bounds": [204, 204]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [2, 195],
+      "position": [14, 707],
       "bounds": [193, 7]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [195, 2],
+      "position": [207, 514],
       "bounds": [7, 193]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [195, 195],
+      "position": [207, 707],
       "bounds": [7, 7],
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 8],
       "bounds": [404, 404]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [395, 2],
+      "position": [403, 10],
       "bounds": [7, 400]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/add-remove-squashed-layers-expected.txt b/third_party/WebKit/LayoutTests/compositing/squashing/add-remove-squashed-layers-expected.txt
index f1c0db6..4b538f3a 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/add-remove-squashed-layers-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/add-remove-squashed-layers-expected.txt
@@ -10,8 +10,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited'",
@@ -39,8 +38,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited'",
@@ -85,8 +83,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited'",
@@ -127,8 +124,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited'",
@@ -187,8 +183,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited'",
@@ -255,8 +250,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited'",
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/clipping-ancestor-expected.txt b/third_party/WebKit/LayoutTests/compositing/squashing/clipping-ancestor-expected.txt
index 8eb3454a..1cde9e5 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/clipping-ancestor-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/clipping-ancestor-expected.txt
@@ -9,11 +9,11 @@
     {
       "name": "Ancestor Clipping Layer",
       "position": [8, 8],
-      "bounds": [200, 10],
-      "shouldFlattenTransform": false
+      "bounds": [200, 10]
     },
     {
       "name": "LayoutBlockFlow DIV id='inner'",
+      "position": [8, 8],
       "bounds": [200, 10],
       "contentsOpaque": true,
       "drawsContent": true,
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/composited-bounds-for-negative-z-expected.txt b/third_party/WebKit/LayoutTests/compositing/squashing/composited-bounds-for-negative-z-expected.txt
index fc09aae2..44ad382 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/composited-bounds-for-negative-z-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/composited-bounds-for-negative-z-expected.txt
@@ -27,30 +27,30 @@
       "name": "LayoutBlockFlow DIV",
       "position": [108, 100],
       "bounds": [300, 300],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [285, 300],
-      "shouldFlattenTransform": false
+      "position": [108, 100],
+      "bounds": [285, 300]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [108, 100],
       "bounds": [285, 1000]
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [108, 100],
       "bounds": [300, 300]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [285, 0],
+      "position": [393, 100],
       "bounds": [15, 300]
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV",
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/invisible-layers-should-not-affect-geometry-expected.txt b/third_party/WebKit/LayoutTests/compositing/squashing/invisible-layers-should-not-affect-geometry-expected.txt
index 67c5c1a..da22cfc 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/invisible-layers-should-not-affect-geometry-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/invisible-layers-should-not-affect-geometry-expected.txt
@@ -7,8 +7,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited box'",
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/move-squashing-layer-expected.txt b/third_party/WebKit/LayoutTests/compositing/squashing/move-squashing-layer-expected.txt
index fb8976ff..bf707a7 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/move-squashing-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/move-squashing-layer-expected.txt
@@ -17,8 +17,7 @@
       "backgroundColor": "#FFFF00"
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='host'",
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/no-squashing-for-filters-expected.txt b/third_party/WebKit/LayoutTests/compositing/squashing/no-squashing-for-filters-expected.txt
index 5b73bf1e..6ad5f0b 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/no-squashing-for-filters-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/no-squashing-for-filters-expected.txt
@@ -15,8 +15,7 @@
       "backgroundColor": "#ADD8E6"
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='trysquashed'",
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/no-squashing-into-fixed-position-that-clips-expected.txt b/third_party/WebKit/LayoutTests/compositing/squashing/no-squashing-into-fixed-position-that-clips-expected.txt
index 083a329..93dff79 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/no-squashing-into-fixed-position-that-clips-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/no-squashing-into-fixed-position-that-clips-expected.txt
@@ -16,11 +16,12 @@
     },
     {
       "name": "Child Containment Layer",
+      "position": [0, 50],
       "bounds": [800, 550]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='compositedlayer'",
-      "position": [400, -10],
+      "position": [400, 40],
       "bounds": [24, 100],
       "contentsOpaque": true,
       "drawsContent": true,
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/opacity-squashed-owner-expected.txt b/third_party/WebKit/LayoutTests/compositing/squashing/opacity-squashed-owner-expected.txt
index 656dd0d..62c9e12 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/opacity-squashed-owner-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/opacity-squashed-owner-expected.txt
@@ -7,8 +7,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow DIV id='target' class='composited box opaque'",
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/repaint-child-of-squashed-expected.txt b/third_party/WebKit/LayoutTests/compositing/squashing/repaint-child-of-squashed-expected.txt
index 76d3254..39c476f 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/repaint-child-of-squashed-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/repaint-child-of-squashed-expected.txt
@@ -8,8 +8,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited box behind'",
@@ -37,8 +36,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited box behind'",
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/squash-above-fixed-1-expected.txt b/third_party/WebKit/LayoutTests/compositing/squashing/squash-above-fixed-1-expected.txt
index 8ede13cc..d9b826db 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/squash-above-fixed-1-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/squash-above-fixed-1-expected.txt
@@ -20,8 +20,7 @@
       "backgroundColor": "#D3D3D3"
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='paragraph-b' class='overlapping lime'",
@@ -84,8 +83,7 @@
       "backgroundColor": "#D3D3D3"
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='paragraph-c' class='overlapping cyan'",
@@ -188,8 +186,7 @@
       "backgroundColor": "#D3D3D3"
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='paragraph-c' class='overlapping cyan'",
@@ -252,8 +249,7 @@
       "backgroundColor": "#D3D3D3"
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='paragraph-d' class='overlapping lime'",
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/squash-above-fixed-2-expected.txt b/third_party/WebKit/LayoutTests/compositing/squashing/squash-above-fixed-2-expected.txt
index b511775..0c95f92 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/squash-above-fixed-2-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/squash-above-fixed-2-expected.txt
@@ -55,6 +55,7 @@
     },
     {
       "name": "LayoutBlockFlow DIV id='compositedInsideFixed'",
+      "position": [0, 80],
       "bounds": [50, 50],
       "contentsOpaque": true,
       "drawsContent": true,
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/squash-above-fixed-3-expected.txt b/third_party/WebKit/LayoutTests/compositing/squashing/squash-above-fixed-3-expected.txt
index 7e9b731..c004800 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/squash-above-fixed-3-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/squash-above-fixed-3-expected.txt
@@ -28,7 +28,7 @@
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='innerFixed'",
-      "position": [0, 50],
+      "position": [100, 150],
       "bounds": [200, 100],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -36,7 +36,7 @@
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='innerScrolling'",
-      "position": [100, 0],
+      "position": [200, 100],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -71,7 +71,7 @@
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='innerFixed'",
-      "position": [0, 60],
+      "position": [100, 160],
       "bounds": [200, 100],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -79,7 +79,7 @@
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='innerScrolling'",
-      "position": [100, 0],
+      "position": [200, 100],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -120,7 +120,7 @@
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='innerFixed'",
-      "position": [0, 160],
+      "position": [100, 260],
       "bounds": [200, 100],
       "contentsOpaque": true,
       "drawsContent": true,
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/squash-compositing-hover-expected.txt b/third_party/WebKit/LayoutTests/compositing/squashing/squash-compositing-hover-expected.txt
index 9e48f84..f71f1212 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/squash-compositing-hover-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/squash-compositing-hover-expected.txt
@@ -12,12 +12,10 @@
     {
       "name": "LayoutBlockFlow DIV class='composited'",
       "position": [8, 8],
-      "transformOrigin": [392, 0],
       "contentsOpaque": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited box behind'",
@@ -47,7 +45,6 @@
     {
       "name": "LayoutBlockFlow DIV class='composited'",
       "position": [8, 8],
-      "transformOrigin": [392, 0],
       "contentsOpaque": true
     },
     {
@@ -59,8 +56,7 @@
       "backgroundColor": "#0000FF"
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='box middle'",
@@ -90,12 +86,10 @@
     {
       "name": "LayoutBlockFlow DIV class='composited'",
       "position": [8, 8],
-      "transformOrigin": [392, 0],
       "contentsOpaque": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited box behind'",
@@ -112,8 +106,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='box middle2'",
@@ -143,12 +136,10 @@
     {
       "name": "LayoutBlockFlow DIV class='composited'",
       "position": [8, 8],
-      "transformOrigin": [392, 0],
       "contentsOpaque": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited box behind'",
@@ -186,12 +177,10 @@
     {
       "name": "LayoutBlockFlow DIV class='composited'",
       "position": [8, 8],
-      "transformOrigin": [392, 0],
       "contentsOpaque": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited box behind'",
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/squash-onto-distant-relative-expected.txt b/third_party/WebKit/LayoutTests/compositing/squashing/squash-onto-distant-relative-expected.txt
index 92e6c23b..47b57bf 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/squash-onto-distant-relative-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/squash-onto-distant-relative-expected.txt
@@ -7,8 +7,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='squashing'",
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/squash-onto-nephew-expected.txt b/third_party/WebKit/LayoutTests/compositing/squashing/squash-onto-nephew-expected.txt
index a8bfed5..5eee243d 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/squash-onto-nephew-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/squash-onto-nephew-expected.txt
@@ -7,8 +7,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited box behind'",
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/squash-onto-transform-backing-expected.txt b/third_party/WebKit/LayoutTests/compositing/squashing/squash-onto-transform-backing-expected.txt
index 868c246..021df647 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/squash-onto-transform-backing-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/squash-onto-transform-backing-expected.txt
@@ -7,8 +7,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='compositedAndRotated box behind'",
@@ -17,12 +16,7 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#0000FF",
-      "transform": [
-        [0.707106781186548, 0.707106781186548, 0, 0],
-        [-0.707106781186548, 0.707106781186548, 0, 0],
-        [0, 0, 1, 0],
-        [0, 0, 0, 1]
-      ]
+      "transform": 1
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (positioned) DIV class='box middle')",
@@ -30,6 +24,18 @@
       "bounds": [260, 260],
       "drawsContent": true
     }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [0.707106781186548, 0.707106781186548, 0, 0],
+        [-0.707106781186548, 0.707106781186548, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, 0, 1]
+      ],
+      "origin": [50, 50]
+    }
   ]
 }
 
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/squash-same-transform-ancestor-expected.txt b/third_party/WebKit/LayoutTests/compositing/squashing/squash-same-transform-ancestor-expected.txt
index a891dabd..78836224 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/squash-same-transform-ancestor-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/squash-same-transform-ancestor-expected.txt
@@ -13,29 +13,40 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#008000",
+      "transform": 1
+    },
+    {
+      "name": "Squashing Containment Layer",
+      "position": [8, 8],
+      "transform": 1
+    },
+    {
+      "name": "LayoutBlockFlow (positioned) DIV id='squashing'",
+      "position": [8, 8],
+      "bounds": [1, 1],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
+    },
+    {
+      "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (positioned) DIV id='squashed')",
+      "position": [-92, 8],
+      "bounds": [200, 200],
+      "drawsContent": true,
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
       "transform": [
         [0.866025403784439, -0.5, 0, 0],
         [0.5, 0.866025403784439, 0, 0],
         [0, 0, 1, 0],
         [100, 100, 0, 1]
-      ]
-    },
-    {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
-    },
-    {
-      "name": "LayoutBlockFlow (positioned) DIV id='squashing'",
-      "bounds": [1, 1],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "backgroundColor": "#FFFFFF"
-    },
-    {
-      "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (positioned) DIV id='squashed')",
-      "position": [-100, 0],
-      "bounds": [200, 200],
-      "drawsContent": true
+      ],
+      "origin": [50, 50]
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/squash-simple-expected.txt b/third_party/WebKit/LayoutTests/compositing/squashing/squash-simple-expected.txt
index 8e3638d..8c1f595 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/squash-simple-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/squash-simple-expected.txt
@@ -7,8 +7,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited box behind'",
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/squash-three-layers-expected.txt b/third_party/WebKit/LayoutTests/compositing/squashing/squash-three-layers-expected.txt
index 9e9c9dd..1e95b63 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/squash-three-layers-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/squash-three-layers-expected.txt
@@ -7,8 +7,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited box behind'",
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/squash-transform-expected.txt b/third_party/WebKit/LayoutTests/compositing/squashing/squash-transform-expected.txt
index df62332..fd3040a 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/squash-transform-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/squash-transform-expected.txt
@@ -15,8 +15,7 @@
       "backgroundColor": "#0000FF"
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='box middle'",
@@ -25,12 +24,7 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#00FF00",
-      "transform": [
-        [0.707106781186548, 0.707106781186548, 0, 0],
-        [-0.707106781186548, 0.707106781186548, 0, 0],
-        [0, 0, 1, 0],
-        [0, 0, 0, 1]
-      ]
+      "transform": 1
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (positioned) DIV class='box top')",
@@ -38,6 +32,18 @@
       "bounds": [100, 100],
       "drawsContent": true
     }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [0.707106781186548, 0.707106781186548, 0, 0],
+        [-0.707106781186548, 0.707106781186548, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, 0, 1]
+      ],
+      "origin": [50, 50]
+    }
   ]
 }
 
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/squash-transform-repainting-child-expected.txt b/third_party/WebKit/LayoutTests/compositing/squashing/squash-transform-repainting-child-expected.txt
index a5e7976c..3ab270b 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/squash-transform-repainting-child-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/squash-transform-repainting-child-expected.txt
@@ -16,8 +16,7 @@
       "backgroundColor": "#0000FF"
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='box middle'",
@@ -26,12 +25,7 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#00FF00",
-      "transform": [
-        [0.707106781186548, 0.707106781186548, 0, 0],
-        [-0.707106781186548, 0.707106781186548, 0, 0],
-        [0, 0, 1, 0],
-        [0, 0, 0, 1]
-      ]
+      "transform": 1
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (positioned) DIV class='box top')",
@@ -39,6 +33,18 @@
       "bounds": [100, 100],
       "drawsContent": true
     }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [0.707106781186548, 0.707106781186548, 0, 0],
+        [-0.707106781186548, 0.707106781186548, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, 0, 1]
+      ],
+      "origin": [50, 50]
+    }
   ]
 }
 CASE 2, hovering over the outer div
@@ -59,8 +65,7 @@
       "backgroundColor": "#0000FF"
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='box middle'",
@@ -69,19 +74,14 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#008000",
-      "transform": [
-        [0.707106781186548, 0.707106781186548, 0, 0],
-        [-0.707106781186548, 0.707106781186548, 0, 0],
-        [0, 0, 1, 0],
-        [0, 0, 0, 1]
-      ],
       "paintInvalidations": [
         {
           "object": "LayoutBlockFlow (positioned) DIV class='box middle'",
           "rect": [0, 0, 100, 100],
           "reason": "style change"
         }
-      ]
+      ],
+      "transform": 1
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (positioned) DIV class='box top')",
@@ -90,6 +90,18 @@
       "drawsContent": true
     }
   ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [0.707106781186548, 0.707106781186548, 0, 0],
+        [-0.707106781186548, 0.707106781186548, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, 0, 1]
+      ],
+      "origin": [50, 50]
+    }
+  ],
   "objectPaintInvalidations": [
     {
       "object": "LayoutBlockFlow (positioned) DIV class='box middle'",
@@ -115,8 +127,7 @@
       "backgroundColor": "#0000FF"
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='box middle'",
@@ -125,12 +136,6 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#008000",
-      "transform": [
-        [0.707106781186548, 0.707106781186548, 0, 0],
-        [-0.707106781186548, 0.707106781186548, 0, 0],
-        [0, 0, 1, 0],
-        [0, 0, 0, 1]
-      ],
       "paintInvalidations": [
         {
           "object": "LayoutBlockFlow (positioned) DIV class='box middle'",
@@ -142,7 +147,8 @@
           "rect": [20, 25, 50, 50],
           "reason": "style change"
         }
-      ]
+      ],
+      "transform": 1
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (positioned) DIV class='box top')",
@@ -151,6 +157,18 @@
       "drawsContent": true
     }
   ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [0.707106781186548, 0.707106781186548, 0, 0],
+        [-0.707106781186548, 0.707106781186548, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, 0, 1]
+      ],
+      "origin": [50, 50]
+    }
+  ],
   "objectPaintInvalidations": [
     {
       "object": "LayoutBlockFlow (positioned) DIV class='box middle'",
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/squash-transform-repainting-transformed-child-expected.txt b/third_party/WebKit/LayoutTests/compositing/squashing/squash-transform-repainting-transformed-child-expected.txt
index d2a68910..de9753f 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/squash-transform-repainting-transformed-child-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/squash-transform-repainting-transformed-child-expected.txt
@@ -16,8 +16,7 @@
       "backgroundColor": "#0000FF"
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='box middle'",
@@ -26,12 +25,7 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#00FF00",
-      "transform": [
-        [0.927183854566787, 0.374606593415912, 0, 0],
-        [-0.374606593415912, 0.927183854566787, 0, 0],
-        [0, 0, 1, 0],
-        [0, 0, 0, 1]
-      ]
+      "transform": 1
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (positioned) DIV class='box top')",
@@ -39,6 +33,18 @@
       "bounds": [100, 100],
       "drawsContent": true
     }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [0.927183854566787, 0.374606593415912, 0, 0],
+        [-0.374606593415912, 0.927183854566787, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, 0, 1]
+      ],
+      "origin": [50, 50]
+    }
   ]
 }
 CASE 2, hovering over the outer div
@@ -59,8 +65,7 @@
       "backgroundColor": "#0000FF"
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='box middle'",
@@ -69,19 +74,14 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#008000",
-      "transform": [
-        [0.927183854566787, 0.374606593415912, 0, 0],
-        [-0.374606593415912, 0.927183854566787, 0, 0],
-        [0, 0, 1, 0],
-        [0, 0, 0, 1]
-      ],
       "paintInvalidations": [
         {
           "object": "LayoutBlockFlow (positioned) DIV class='box middle'",
           "rect": [0, 0, 100, 100],
           "reason": "style change"
         }
-      ]
+      ],
+      "transform": 1
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (positioned) DIV class='box top')",
@@ -90,6 +90,18 @@
       "drawsContent": true
     }
   ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [0.927183854566787, 0.374606593415912, 0, 0],
+        [-0.374606593415912, 0.927183854566787, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, 0, 1]
+      ],
+      "origin": [50, 50]
+    }
+  ],
   "objectPaintInvalidations": [
     {
       "object": "LayoutBlockFlow (positioned) DIV class='box middle'",
@@ -115,8 +127,7 @@
       "backgroundColor": "#0000FF"
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='box middle'",
@@ -125,12 +136,6 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#008000",
-      "transform": [
-        [0.927183854566787, 0.374606593415912, 0, 0],
-        [-0.374606593415912, 0.927183854566787, 0, 0],
-        [0, 0, 1, 0],
-        [0, 0, 0, 1]
-      ],
       "paintInvalidations": [
         {
           "object": "LayoutBlockFlow (positioned) DIV class='box middle'",
@@ -142,7 +147,8 @@
           "rect": [12, 17, 66, 66],
           "reason": "style change"
         }
-      ]
+      ],
+      "transform": 1
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (positioned) DIV class='box top')",
@@ -151,6 +157,18 @@
       "drawsContent": true
     }
   ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [0.927183854566787, 0.374606593415912, 0, 0],
+        [-0.374606593415912, 0.927183854566787, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, 0, 1]
+      ],
+      "origin": [50, 50]
+    }
+  ],
   "objectPaintInvalidations": [
     {
       "object": "LayoutBlockFlow (positioned) DIV class='box middle'",
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/squashed-layer-loses-graphicslayer-expected.txt b/third_party/WebKit/LayoutTests/compositing/squashing/squashed-layer-loses-graphicslayer-expected.txt
index c42aa4b..db96d72 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/squashed-layer-loses-graphicslayer-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/squashed-layer-loses-graphicslayer-expected.txt
@@ -10,8 +10,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='forceComposited' class='composited underneath'",
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/squashed-repaints-expected.txt b/third_party/WebKit/LayoutTests/compositing/squashing/squashed-repaints-expected.txt
index fdd10bf5..617e460 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/squashed-repaints-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/squashed-repaints-expected.txt
@@ -10,8 +10,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited'",
@@ -39,8 +38,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited'",
@@ -81,8 +79,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited'",
@@ -132,8 +129,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited'",
@@ -183,8 +179,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited'",
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/squashing-inside-perspective-expected.txt b/third_party/WebKit/LayoutTests/compositing/squashing/squashing-inside-perspective-expected.txt
index 89737c3..4697097b 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/squashing-inside-perspective-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/squashing-inside-perspective-expected.txt
@@ -13,17 +13,11 @@
     },
     {
       "name": "Child Transform Layer",
-      "shouldFlattenTransform": false,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, -0.001],
-        [0, 0, 0, 1]
-      ]
+      "transform": 1
     },
     {
       "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV",
@@ -31,16 +25,35 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#00008B",
+      "transform": 2
+    },
+    {
+      "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (positioned) DIV)",
+      "drawsContent": true,
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, -0.001],
+        [0, 0, 0, 1]
+      ],
+      "origin": [0, 0],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 2,
+      "parent": 1,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
         [0, 74, 200, 1]
       ]
-    },
-    {
-      "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (positioned) DIV)",
-      "drawsContent": true
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/squashing-sparsity-heuristic-expected.txt b/third_party/WebKit/LayoutTests/compositing/squashing/squashing-sparsity-heuristic-expected.txt
index 6551a9f..b65eaca 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/squashing-sparsity-heuristic-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/squashing-sparsity-heuristic-expected.txt
@@ -7,8 +7,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited'",
@@ -25,8 +24,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='B' class='overlap2'",
diff --git a/third_party/WebKit/LayoutTests/compositing/update-paint-phases-expected.txt b/third_party/WebKit/LayoutTests/compositing/update-paint-phases-expected.txt
index a33515de..305343e 100644
--- a/third_party/WebKit/LayoutTests/compositing/update-paint-phases-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/update-paint-phases-expected.txt
@@ -16,7 +16,6 @@
       "name": "LayoutBlockFlow DIV class='scroller'",
       "position": [8, 8],
       "bounds": [102, 102],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "paintingPhases": [
         "GraphicsLayerPaintBackground",
@@ -27,9 +26,8 @@
     },
     {
       "name": "Scrolling Layer",
-      "position": [1, 1],
+      "position": [9, 9],
       "bounds": [85, 85],
-      "shouldFlattenTransform": false,
       "paintingPhases": [
         "GraphicsLayerPaintBackground",
         "GraphicsLayerPaintForeground",
@@ -39,6 +37,7 @@
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [9, 9],
       "bounds": [85, 120],
       "drawsContent": true,
       "paintingPhases": [
@@ -49,6 +48,7 @@
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 8],
       "bounds": [102, 102],
       "paintingPhases": [
         "GraphicsLayerPaintBackground",
@@ -59,7 +59,7 @@
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [1, 86],
+      "position": [9, 94],
       "bounds": [85, 15],
       "paintingPhases": [
         "GraphicsLayerPaintBackground",
@@ -70,7 +70,7 @@
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [86, 1],
+      "position": [94, 9],
       "bounds": [15, 85],
       "paintingPhases": [
         "GraphicsLayerPaintBackground",
@@ -81,7 +81,7 @@
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [86, 86],
+      "position": [94, 94],
       "bounds": [15, 15],
       "drawsContent": true,
       "paintingPhases": [
diff --git a/third_party/WebKit/LayoutTests/css3/blending/mix-blend-mode-2nd-stacking-context-composited-expected.txt b/third_party/WebKit/LayoutTests/css3/blending/mix-blend-mode-2nd-stacking-context-composited-expected.txt
index 355495b..f942244b 100644
--- a/third_party/WebKit/LayoutTests/css3/blending/mix-blend-mode-2nd-stacking-context-composited-expected.txt
+++ b/third_party/WebKit/LayoutTests/css3/blending/mix-blend-mode-2nd-stacking-context-composited-expected.txt
@@ -13,7 +13,6 @@
     {
       "name": "LayoutBlockFlow (positioned) DIV class='accelerated stacking-context'",
       "position": [8, 8],
-      "transformOrigin": [0, 0],
       "bounds": [160, 90],
       "contentsOpaque": true,
       "drawsContent": true,
diff --git a/third_party/WebKit/LayoutTests/css3/blending/mix-blend-mode-composited-reason-children-expected.txt b/third_party/WebKit/LayoutTests/css3/blending/mix-blend-mode-composited-reason-children-expected.txt
index 598963c..122f3517 100644
--- a/third_party/WebKit/LayoutTests/css3/blending/mix-blend-mode-composited-reason-children-expected.txt
+++ b/third_party/WebKit/LayoutTests/css3/blending/mix-blend-mode-composited-reason-children-expected.txt
@@ -19,6 +19,7 @@
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='stacking-context'",
+      "position": [8, 8],
       "bounds": [160, 90],
       "isolate": true,
       "contentsOpaque": true,
@@ -27,6 +28,7 @@
     },
     {
       "name": "LayoutBlockFlow DIV class='blended'",
+      "position": [8, 8],
       "bounds": [160, 90],
       "blendMode": "multiply",
       "drawsContent": true,
@@ -34,10 +36,12 @@
     },
     {
       "name": "LayoutImage IMG class='accelerated'",
+      "position": [8, 8],
       "bounds": [160, 90]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='stacking-context' (foreground) Layer",
+      "position": [8, 8],
       "drawsContent": true
     },
     {
diff --git a/third_party/WebKit/LayoutTests/css3/blending/mix-blend-mode-isolation-2-stacking-contexts-expected.txt b/third_party/WebKit/LayoutTests/css3/blending/mix-blend-mode-isolation-2-stacking-contexts-expected.txt
index 54cac95..624b51f 100644
--- a/third_party/WebKit/LayoutTests/css3/blending/mix-blend-mode-isolation-2-stacking-contexts-expected.txt
+++ b/third_party/WebKit/LayoutTests/css3/blending/mix-blend-mode-isolation-2-stacking-contexts-expected.txt
@@ -19,6 +19,7 @@
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='stacking-context'",
+      "position": [8, 8],
       "bounds": [160, 90],
       "isolate": true,
       "contentsOpaque": true,
@@ -27,11 +28,13 @@
     },
     {
       "name": "LayoutImage IMG class='accelerated blended'",
+      "position": [8, 8],
       "bounds": [160, 90],
       "blendMode": "multiply"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='stacking-context' (foreground) Layer",
+      "position": [8, 8],
       "drawsContent": true
     },
     {
@@ -43,6 +46,7 @@
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='stacking-context'",
+      "position": [8, 8],
       "bounds": [160, 90],
       "isolate": true,
       "contentsOpaque": true,
@@ -51,11 +55,13 @@
     },
     {
       "name": "LayoutImage IMG class='accelerated blended'",
+      "position": [8, 8],
       "bounds": [160, 90],
       "blendMode": "multiply"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='accelerated stacking-context' (foreground) Layer",
+      "position": [8, 8],
       "drawsContent": true
     },
     {
diff --git a/third_party/WebKit/LayoutTests/css3/blending/mix-blend-mode-isolation-layer-expected.txt b/third_party/WebKit/LayoutTests/css3/blending/mix-blend-mode-isolation-layer-expected.txt
index 2a533981..e780de2 100644
--- a/third_party/WebKit/LayoutTests/css3/blending/mix-blend-mode-isolation-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/css3/blending/mix-blend-mode-isolation-layer-expected.txt
@@ -21,6 +21,7 @@
     },
     {
       "name": "LayoutImage IMG class='accelerated blended'",
+      "position": [8, 8],
       "bounds": [160, 90],
       "blendMode": "multiply"
     },
diff --git a/third_party/WebKit/LayoutTests/css3/blending/mix-blend-mode-isolation-remove-expected.txt b/third_party/WebKit/LayoutTests/css3/blending/mix-blend-mode-isolation-remove-expected.txt
index 3847636..12f9e2e 100644
--- a/third_party/WebKit/LayoutTests/css3/blending/mix-blend-mode-isolation-remove-expected.txt
+++ b/third_party/WebKit/LayoutTests/css3/blending/mix-blend-mode-isolation-remove-expected.txt
@@ -17,6 +17,7 @@
     },
     {
       "name": "LayoutBlockFlow DIV id='intermediary' class='accelerated-no-stacking-context'",
+      "position": [8, 8],
       "bounds": [784, 90],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -25,6 +26,7 @@
     },
     {
       "name": "LayoutImage IMG class='accelerated blended'",
+      "position": [8, 8],
       "bounds": [160, 90],
       "blendMode": "multiply"
     }
diff --git a/third_party/WebKit/LayoutTests/css3/filters/filtered-compositing-descendant-expected.txt b/third_party/WebKit/LayoutTests/css3/filters/filtered-compositing-descendant-expected.txt
index 52e869b..4cd10a9 100644
--- a/third_party/WebKit/LayoutTests/css3/filters/filtered-compositing-descendant-expected.txt
+++ b/third_party/WebKit/LayoutTests/css3/filters/filtered-compositing-descendant-expected.txt
@@ -19,6 +19,12 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#FF0000",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
index 7ef66dc..3cac3d28 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -117846,6 +117846,31 @@
      {}
     ]
    ],
+   "streams/readable-byte-streams/properties-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "streams/readable-byte-streams/properties.dedicatedworker-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "streams/readable-byte-streams/properties.js": [
+    [
+     {}
+    ]
+   ],
+   "streams/readable-byte-streams/properties.serviceworker.https-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "streams/readable-byte-streams/properties.sharedworker-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "streams/readable-streams/bad-strategies.js": [
     [
      {}
@@ -136912,6 +136937,12 @@
      {}
     ]
    ],
+   "css/css-transforms-2/transforms-support-calc.html": [
+    [
+     "/css/css-transforms-2/transforms-support-calc.html",
+     {}
+    ]
+   ],
    "css/css-ui-3/box-sizing-027.html": [
     [
      "/css/css-ui-3/box-sizing-027.html",
@@ -137470,6 +137501,12 @@
      {}
     ]
    ],
+   "css/motion-1/offset-supports-calc.html": [
+    [
+     "/css/motion-1/offset-supports-calc.html",
+     {}
+    ]
+   ],
    "css/motion-1/parsing/offset-anchor-parsing-invalid.html": [
     [
      "/css/motion-1/parsing/offset-anchor-parsing-invalid.html",
@@ -175314,6 +175351,30 @@
      {}
     ]
    ],
+   "streams/readable-byte-streams/properties.dedicatedworker.html": [
+    [
+     "/streams/readable-byte-streams/properties.dedicatedworker.html",
+     {}
+    ]
+   ],
+   "streams/readable-byte-streams/properties.html": [
+    [
+     "/streams/readable-byte-streams/properties.html",
+     {}
+    ]
+   ],
+   "streams/readable-byte-streams/properties.serviceworker.https.html": [
+    [
+     "/streams/readable-byte-streams/properties.serviceworker.https.html",
+     {}
+    ]
+   ],
+   "streams/readable-byte-streams/properties.sharedworker.html": [
+    [
+     "/streams/readable-byte-streams/properties.sharedworker.html",
+     {}
+    ]
+   ],
    "streams/readable-streams/bad-strategies.dedicatedworker.html": [
     [
      "/streams/readable-streams/bad-strategies.dedicatedworker.html",
@@ -176486,6 +176547,12 @@
      {}
     ]
    ],
+   "wasm/many-memories.window.js": [
+    [
+     "/wasm/many-memories.window.html",
+     {}
+    ]
+   ],
    "wasm/wasm_indexeddb_test.html": [
     [
      "/wasm/wasm_indexeddb_test.html",
@@ -229569,6 +229636,10 @@
    "cf9af05cb3d0f2a54fce7554f15cf0159c16a5a7",
    "reftest"
   ],
+  "css/css-transforms-2/transforms-support-calc.html": [
+   "f179489200392d7af2e33a9ac2123c51b9aac21d",
+   "testharness"
+  ],
   "css/css-transforms-2/transofrmed-preserve-3d-1.html": [
    "6b9049d0a41eaa593b0d7aa2eaceebe952850851",
    "reftest"
@@ -238661,6 +238732,10 @@
    "09f4897e2d2fa99303edb59e2872a9a373db3e26",
    "support"
   ],
+  "css/motion-1/offset-supports-calc.html": [
+   "f893e408a6e958d0ac5b26489ffe10374735f053",
+   "testharness"
+  ],
   "css/motion-1/parsing/offset-anchor-parsing-invalid.html": [
    "b48194c7ee35af7d114fd514f060ea9e8aae6372",
    "testharness"
@@ -246598,7 +246673,7 @@
    "support"
   ],
   "feature-policy/resources/featurepolicy.js": [
-   "1ca3bc48c7617dc473be05149a3cd462408afcf4",
+   "99eeea227030740ce1aac7b4bf7c970dde9a0bea",
    "support"
   ],
   "feature-policy/resources/redirect-on-load.html": [
@@ -273766,7 +273841,7 @@
    "testharness"
   ],
   "payment-request/payment-allowed-by-feature-policy.https.sub.html.headers": [
-   "fd48787138bbac80eb51d9f35739f90940a51823",
+   "038c90f26cb5c16047c294aa35a0b0251324dbc6",
    "support"
   ],
   "payment-request/payment-default-feature-policy.https.sub.html": [
@@ -273778,7 +273853,7 @@
    "testharness"
   ],
   "payment-request/payment-disabled-by-feature-policy.https.sub.html.headers": [
-   "60797d4515749de7c8fc7748036e0f449853ca04",
+   "09f612159dc367bad5febc8e0a724f0a284517d5",
    "support"
   ],
   "payment-request/payment-request-abort-method.https-expected.txt": [
@@ -283334,7 +283409,7 @@
    "support"
   ],
   "service-workers/service-worker/clients-matchall-client-types.https.html": [
-   "3219697b2d6fb9694ad4db1e2d157807b5e5dbcb",
+   "7c522e90fd156ba8b044acd4e606a0242b93f11a",
    "testharness"
   ],
   "service-workers/service-worker/clients-matchall-exact-controller.https.html": [
@@ -285706,7 +285781,7 @@
    "testharness"
   ],
   "streams/byte-length-queuing-strategy.js": [
-   "e4b248c7de8b85df9ed01d707cf2dfcfd9a5bcb0",
+   "7ff2e4b0e5e51cd7a2769f4d39cd4eb7e5e1c8bd",
    "support"
   ],
   "streams/byte-length-queuing-strategy.serviceworker.https.html": [
@@ -285726,7 +285801,7 @@
    "testharness"
   ],
   "streams/count-queuing-strategy.js": [
-   "33f8db7addcc8e01d798b9199b6d78ad35d8a243",
+   "0668d6cba799e52f793778c92dce2e7c572712db",
    "support"
   ],
   "streams/count-queuing-strategy.serviceworker.https.html": [
@@ -285989,6 +286064,42 @@
    "44f9ceaa3bfc9d8b92885997d322486bd0f237a6",
    "testharness"
   ],
+  "streams/readable-byte-streams/properties-expected.txt": [
+   "2b79875031b79439c79ee426ea9d0de93b2ad537",
+   "support"
+  ],
+  "streams/readable-byte-streams/properties.dedicatedworker-expected.txt": [
+   "2b79875031b79439c79ee426ea9d0de93b2ad537",
+   "support"
+  ],
+  "streams/readable-byte-streams/properties.dedicatedworker.html": [
+   "0d766237560b16ddb1bfcd02e701089132f1b3ec",
+   "testharness"
+  ],
+  "streams/readable-byte-streams/properties.html": [
+   "5daad347136ccd82e952ba0f29894c4634ab4e6d",
+   "testharness"
+  ],
+  "streams/readable-byte-streams/properties.js": [
+   "4fd71882c2a1b8c35fb24a10599a6b90a0f32730",
+   "support"
+  ],
+  "streams/readable-byte-streams/properties.serviceworker.https-expected.txt": [
+   "258a13ea43322d74d92907cafbae46687f851dff",
+   "support"
+  ],
+  "streams/readable-byte-streams/properties.serviceworker.https.html": [
+   "2ef8fc878249c429a89e0748e6a98fac47c1a99a",
+   "testharness"
+  ],
+  "streams/readable-byte-streams/properties.sharedworker-expected.txt": [
+   "2b79875031b79439c79ee426ea9d0de93b2ad537",
+   "support"
+  ],
+  "streams/readable-byte-streams/properties.sharedworker.html": [
+   "5c855e897d1143092ecc10b58268e6a576882184",
+   "testharness"
+  ],
   "streams/readable-streams/bad-strategies.dedicatedworker.html": [
    "269e32606201603b326048f42573c8535c060a18",
    "testharness"
@@ -286098,7 +286209,7 @@
    "testharness"
   ],
   "streams/readable-streams/default-reader.js": [
-   "4bf42e5e2f45275c98122fd6e884d7af0dee1e77",
+   "8746e2c94c2bc28431aefaae71d83f87c5738cde",
    "support"
   ],
   "streams/readable-streams/default-reader.serviceworker.https.html": [
@@ -286162,7 +286273,7 @@
    "testharness"
   ],
   "streams/readable-streams/general.js": [
-   "ef0060b256dfde2195f43529a1c1a0c63e290f16",
+   "e5ea14274f267ba4579627dd12b81e0863271328",
    "support"
   ],
   "streams/readable-streams/general.serviceworker.https-expected.txt": [
@@ -286466,7 +286577,7 @@
    "testharness"
   ],
   "streams/writable-streams/properties.js": [
-   "651d62037ceff95818e8cd33c078a31e09dafd5c",
+   "cc5f851c607b8dc681cbdacb20362689d7259dea",
    "support"
   ],
   "streams/writable-streams/properties.serviceworker.https.html": [
@@ -287665,6 +287776,10 @@
    "acdf9d22c042ea3b2637c14b1576b4c8ffb4e97a",
    "support"
   ],
+  "wasm/many-memories.window.js": [
+   "591b015662a6d181677892ec9c87f39bb36bbc23",
+   "testharness"
+  ],
   "wasm/resources/blank.html": [
    "0ddb4f1cf84729ed673295719ec58a3e5d600a12",
    "support"
@@ -290830,7 +290945,7 @@
    "testharness"
   ],
   "webusb/usb-allowed-by-feature-policy.https.sub.html.headers": [
-   "a579c20e4a57dc30372470c685922e6a973a6d84",
+   "2d7c5aef94d200bdf580a4ee3c7fdc9356dba183",
    "support"
   ],
   "webusb/usb-default-feature-policy.https.sub.html": [
@@ -290842,7 +290957,7 @@
    "testharness"
   ],
   "webusb/usb-disabled-by-feature-policy.https.sub.html.headers": [
-   "c8b3c972c90674c75d652a31a8d0b28eec8ca6e7",
+   "7cc713de57caf823d0f778d943d6e7bb3900fb1e",
    "support"
   ],
   "webusb/usb-manual.https.html": [
diff --git a/third_party/WebKit/LayoutTests/external/wpt/2dcontext/imagebitmap/createImageBitmap-drawImage-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/2dcontext/imagebitmap/createImageBitmap-drawImage-expected.txt
deleted file mode 100644
index 60b90bf..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/2dcontext/imagebitmap/createImageBitmap-drawImage-expected.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-This is a testharness.js-based test.
-PASS createImageBitmap from a HTMLImageElement, and drawImage on the created ImageBitmap
-PASS createImageBitmap from a Blob, and drawImage on the created ImageBitmap
-FAIL createImageBitmap from a HTMLCanvasElement, and drawImage on the created ImageBitmap assert_not_equals: got disallowed value undefined
-PASS createImageBitmap from an ImageBitmap, and drawImage on the created ImageBitmap
-PASS createImageBitmap from an ImageData, and drawImage on the created ImageBitmap
-PASS createImageBitmap from a HTMLVideoElement, and drawImage on the created ImageBitmap
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/access-control-preflight-request-header-lowercase.htm b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/access-control-preflight-request-header-lowercase.htm
new file mode 100644
index 0000000..d88cac8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/access-control-preflight-request-header-lowercase.htm
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Access-Control-Request-Headers values should be lowercase</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/common/get-host-info.sub.js"></script>
+  </head>
+  <body>
+    <script type="text/javascript">
+    async_test(function(test) {
+      const xhr = new XMLHttpRequest;
+
+      xhr.open("GET", get_host_info().HTTP_REMOTE_ORIGIN + "/XMLHttpRequest/resources/access-control-preflight-request-header-lowercase.py");
+
+      xhr.setRequestHeader("X-Test", "foobar");
+
+      xhr.onerror = test.unreached_func("Error occurred.");
+
+      xhr.onload = test.step_func_done(function() {
+        assert_equals(xhr.status, 200);
+        assert_equals(xhr.responseText, "PASS");
+      });
+
+      xhr.send();
+    }, "Request with uppercase header set");
+    </script>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/resources/access-control-preflight-request-header-lowercase.py b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/resources/access-control-preflight-request-header-lowercase.py
new file mode 100644
index 0000000..d35b89b9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/resources/access-control-preflight-request-header-lowercase.py
@@ -0,0 +1,16 @@
+def main(request, response):
+    response.headers.set("Cache-Control", "no-store")
+    response.headers.set("Access-Control-Allow-Origin", "*")
+    response.headers.set("Access-Control-Max-Age", 0)
+
+    if request.method == "OPTIONS":
+        if "x-test" in [header.strip(" ") for header in
+                        request.headers.get("Access-Control-Request-Headers").split(",")]:
+            response.headers.set("Access-Control-Allow-Headers", "X-Test")
+        else:
+            response.status = 400
+    elif request.method == "GET":
+        if request.headers.get("X-Test"):
+            response.content = "PASS"
+        else:
+            response.status = 400
diff --git a/third_party/WebKit/LayoutTests/external/wpt/audio-output/setSinkId.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/audio-output/setSinkId.https-expected.txt
index 9c401143..39ecceaf 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/audio-output/setSinkId.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/audio-output/setSinkId.https-expected.txt
@@ -2,6 +2,6 @@
 PASS setSinkId on default audio output should always work
 PASS setSinkId fails with NotFoundError on made up deviceid
 PASS List media devices
-FAIL Correctly reacts to setting known deviceid as sinkid 0assert_equals: On known devices, the only possible failure of setSinkId is a securityerror expected "SecurityError" but got "NotFoundError"
+FAIL Correctly reacts to setting known deviceid as sinkid 0 assert_equals: On known devices, the only possible failure of setSinkId is a securityerror expected "SecurityError" but got "NotFoundError"
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms-2/transforms-support-calc.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms-2/transforms-support-calc.html
new file mode 100644
index 0000000..19bacd96
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms-2/transforms-support-calc.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Transform Module Level 2: calc values</title>
+<link rel="author" title="Eric Willigers" href="mailto:ericwilligers@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-transforms-2/">
+<link rel="help" href="https://drafts.csswg.org/css-values-3/#calc-notation">
+<meta name="assert" content="calc values are supported in css-transforms properties.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+  #container {
+    width: 600px;
+    height: 500px;
+    transform-style: preserve-3d;
+  }
+  #target {
+    width: 300px;
+    height: 200px;
+    font-size: 20px;
+  }
+</style>
+</head>
+<body>
+<div id="container">
+  <div id="target"></div>
+</div>
+<script>
+'use strict';
+
+test(function(){
+  target.style = 'translate: calc(30px + 20%) calc(-200px + 100%);';
+  assert_equals(getComputedStyle(target).translate, '90px 0px');
+}, 'translate supports calc');
+
+test(function(){
+  target.style = 'rotate: calc(1turn - 100grad);';
+  assert_equals(getComputedStyle(target).rotate, '270deg');
+}, 'rotate supports calc');
+
+test(function(){
+  target.style = 'scale: calc(5 + 2) calc(5 - 2) calc(5 * 2);';
+  assert_equals(getComputedStyle(target).scale, '7 3 10');
+}, 'scale supports calc');
+
+test(function(){
+  target.style = 'perspective: calc(100px - 3em);';
+  assert_equals(getComputedStyle(target).perspective, '40px');
+}, 'perspective supports calc');
+
+test(function(){
+  target.style = 'perspective-origin: calc(30px + 20%) calc(-200px + 100%);';
+  assert_equals(getComputedStyle(target).perspectiveOrigin, '90px 0px');
+}, 'perspective-origin supports calc');
+
+test(function(){
+  target.style = 'transform: translate(calc(30px + 20%), calc(-200px + 100%)) rotate(calc(1turn - 400grad)) scale(calc(5 + 2), calc(5 - 2));';
+  assert_equals(getComputedStyle(target).transform, 'matrix(7, 0, 0, 3, 90, 0)');
+}, 'transform supports calc');
+
+test(function(){
+  target.style = 'transform-origin: calc(30px + 20%) calc(-200px + 100%);';
+  assert_equals(getComputedStyle(target).transformOrigin, '90px 0px');
+}, 'transform-origin supports calc');
+
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-values-3/OWNERS b/third_party/WebKit/LayoutTests/external/wpt/css/css-values-3/OWNERS
new file mode 100644
index 0000000..ada3963
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-values-3/OWNERS
@@ -0,0 +1,2 @@
+# TEAM: style-dev@chromium.org
+# COMPONENT: Blink>CSS
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css-values/unset-value-storage.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-values-3/unset-value-storage.html
similarity index 89%
rename from third_party/WebKit/LayoutTests/external/wpt/css-values/unset-value-storage.html
rename to third_party/WebKit/LayoutTests/external/wpt/css/css-values-3/unset-value-storage.html
index 9cf13b2..5869e9e 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css-values/unset-value-storage.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-values-3/unset-value-storage.html
@@ -2,6 +2,7 @@
 <meta charset="utf-8">
 <title>Storage of "unset" value</title>
 <meta name="author" title="Xidorn Quan" href="https://www.upsuper.org">
+<link rel="help" href="https://drafts.csswg.org/css-values-3/#common-keywords"/>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <style>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/motion-1/offset-supports-calc.html b/third_party/WebKit/LayoutTests/external/wpt/css/motion-1/offset-supports-calc.html
new file mode 100644
index 0000000..79aa9a9f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/motion-1/offset-supports-calc.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Motion Path Module Level 1: calc values</title>
+<link rel="author" title="Eric Willigers" href="mailto:ericwilligers@chromium.org">
+<link rel="help" href="https://drafts.fxtf.org/motion-1/">
+<link rel="help" href="https://drafts.csswg.org/css-values-3/#calc-notation">
+<meta name="assert" content="calc values are supported in offset properties.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+  #target {
+    font-size: 20px;
+  }
+</style>
+</head>
+<body>
+<div id="target"></div>
+<script>
+'use strict';
+
+test(function(){
+  target.style = 'offset-position: calc(30px + 20%) calc(-200px + 8em + 100%);';
+  assert_equals(getComputedStyle(target).offsetPosition, 'calc(30px + 20%) calc(-40px + 100%)');
+}, 'offset-position supports calc');
+
+test(function(){
+  target.style = 'offset-path: ray(calc(1turn - 100grad) closest-side);';
+  assert_equals(getComputedStyle(target).offsetPath, 'ray(270deg closest-side)');
+}, 'offset-path supports calc');
+
+test(function(){
+  target.style = 'offset-distance: calc(-100px + 50%);';
+  assert_equals(getComputedStyle(target).offsetDistance, 'calc(-100px + 50%)');
+}, 'offset-distance supports calc');
+
+test(function(){
+  target.style = 'offset-rotate: auto calc(1turn - 100grad);';
+  assert_equals(getComputedStyle(target).offsetRotate, 'auto 270deg');
+}, 'offset-rotate supports calc');
+
+test(function(){
+  target.style = 'offset-anchor: calc(30px + 20%) calc(-200px + 8em + 100%);';
+  assert_equals(getComputedStyle(target).offsetAnchor, 'calc(30px + 20%) calc(-40px + 100%)');
+}, 'offset-anchor supports calc');
+
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/feature-policy/resources/featurepolicy.js b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/resources/featurepolicy.js
index 658b254..1d7395a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/feature-policy/resources/featurepolicy.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/resources/featurepolicy.js
@@ -28,7 +28,7 @@
   frame.src = src;
 
   if (typeof feature_name !== 'undefined') {
-    frame.allow.add(feature_name);
+    frame.allow = frame.allow.concat(";" + feature_name);
   }
 
   if (typeof allow_attribute !== 'undefined') {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-data-url-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-data-url-expected.txt
index 3ac6255b..829f50ea 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-data-url-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-data-url-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-FAIL track element data: URL No CORSassert_unreached: got error event Reached unreachable code
+FAIL track element data: URL No CORS assert_unreached: got error event Reached unreachable code
 PASS track element data: URL anonymous
 PASS track element data: URL use-credentials
 Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/historical.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/payment-request/historical.https-expected.txt
index e6077d6c2..b2cb833 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/historical.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/historical.https-expected.txt
@@ -5,7 +5,7 @@
 PASS totalAmount in PaymentResponse
 PASS paymentRequestId in PaymentRequest
 PASS paymentRequestId in PaymentResponse
-FAIL supportedMethods must not support sequence<DOMString>assert_throws: function "() => {
+FAIL supportedMethods must not support sequence<DOMString> assert_throws: function "() => {
     new PaymentRequest([{supportedMethods: methods}], {total: {label: 'bar', amount: {currency: 'BAZ', value: '0'}}});
   }" threw object "[object Object]" ("sequence<DOMString> conversion is not allowed") expected object "[object Object]" ("toString should be called")
 Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-allowed-by-feature-policy.https.sub.html.headers b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-allowed-by-feature-policy.https.sub.html.headers
index 5517dd3..a5c010b 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-allowed-by-feature-policy.https.sub.html.headers
+++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-allowed-by-feature-policy.https.sub.html.headers
@@ -1 +1 @@
-Feature-Policy: {"payment": ["*"]}
+Feature-Policy: payment *
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-disabled-by-feature-policy.https.sub.html.headers b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-disabled-by-feature-policy.https.sub.html.headers
index 8f8b4824..a283677 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-disabled-by-feature-policy.https.sub.html.headers
+++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-disabled-by-feature-policy.https.sub.html.headers
@@ -1 +1 @@
-Feature-Policy: {"payment": []}
+Feature-Policy: payment 'none'
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/clients-matchall-client-types.https.html b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/clients-matchall-client-types.https.html
index 5bb50ec..2496717 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/clients-matchall-client-types.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/clients-matchall-client-types.https.html
@@ -19,9 +19,12 @@
 var expected_only_dedicated_worker = [
     [undefined, undefined, new URL(dedicated_worker_url, location).href, 'worker', 'none']
 ];
+
+// These are explicitly sorted by URL in the service worker script.
 var expected_all_clients = [
-    expected_only_window[0], expected_only_shared_worker[0],
-    expected_only_dedicated_worker[0]
+    expected_only_dedicated_worker[0],
+    expected_only_window[0],
+    expected_only_shared_worker[0],
 ];
 
 function test_matchall(frame, expected, query_options) {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/link-element-register-mime-types.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/link-element-register-mime-types.https-expected.txt
index ae3ae7a6..28bf3a7 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/link-element-register-mime-types.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/link-element-register-mime-types.https-expected.txt
@@ -4,36 +4,36 @@
 FAIL Registering script that imports script with no MIME type assert_unreached: Should have rejected: Registration of no MIME type imported script should fail. Reached unreachable code
 FAIL Registering script that imports script with bad MIME type assert_unreached: Should have rejected: Registration of plain text imported script should fail. Reached unreachable code
 FAIL Registering script with good MIME type application/ecmascript promise_test: Unhandled rejection with value: object "[object Event]"
-PASS Registering script that imports script with good MIME type application/ecmascript 
-PASS Registering script with good MIME type application/javascript 
-PASS Registering script that imports script with good MIME type application/javascript 
+PASS Registering script that imports script with good MIME type application/ecmascript
+PASS Registering script with good MIME type application/javascript
+PASS Registering script that imports script with good MIME type application/javascript
 FAIL Registering script with good MIME type application/x-ecmascript promise_test: Unhandled rejection with value: object "[object Event]"
-PASS Registering script that imports script with good MIME type application/x-ecmascript 
-PASS Registering script with good MIME type application/x-javascript 
-PASS Registering script that imports script with good MIME type application/x-javascript 
+PASS Registering script that imports script with good MIME type application/x-ecmascript
+PASS Registering script with good MIME type application/x-javascript
+PASS Registering script that imports script with good MIME type application/x-javascript
 FAIL Registering script with good MIME type text/ecmascript promise_test: Unhandled rejection with value: object "[object Event]"
-PASS Registering script that imports script with good MIME type text/ecmascript 
-PASS Registering script with good MIME type text/javascript 
-PASS Registering script that imports script with good MIME type text/javascript 
+PASS Registering script that imports script with good MIME type text/ecmascript
+PASS Registering script with good MIME type text/javascript
+PASS Registering script that imports script with good MIME type text/javascript
 FAIL Registering script with good MIME type text/javascript1.0 promise_test: Unhandled rejection with value: object "[object Event]"
-PASS Registering script that imports script with good MIME type text/javascript1.0 
+PASS Registering script that imports script with good MIME type text/javascript1.0
 FAIL Registering script with good MIME type text/javascript1.1 promise_test: Unhandled rejection with value: object "[object Event]"
-PASS Registering script that imports script with good MIME type text/javascript1.1 
+PASS Registering script that imports script with good MIME type text/javascript1.1
 FAIL Registering script with good MIME type text/javascript1.2 promise_test: Unhandled rejection with value: object "[object Event]"
-PASS Registering script that imports script with good MIME type text/javascript1.2 
+PASS Registering script that imports script with good MIME type text/javascript1.2
 FAIL Registering script with good MIME type text/javascript1.3 promise_test: Unhandled rejection with value: object "[object Event]"
-PASS Registering script that imports script with good MIME type text/javascript1.3 
+PASS Registering script that imports script with good MIME type text/javascript1.3
 FAIL Registering script with good MIME type text/javascript1.4 promise_test: Unhandled rejection with value: object "[object Event]"
-PASS Registering script that imports script with good MIME type text/javascript1.4 
+PASS Registering script that imports script with good MIME type text/javascript1.4
 FAIL Registering script with good MIME type text/javascript1.5 promise_test: Unhandled rejection with value: object "[object Event]"
-PASS Registering script that imports script with good MIME type text/javascript1.5 
+PASS Registering script that imports script with good MIME type text/javascript1.5
 FAIL Registering script with good MIME type text/jscript promise_test: Unhandled rejection with value: object "[object Event]"
-PASS Registering script that imports script with good MIME type text/jscript 
+PASS Registering script that imports script with good MIME type text/jscript
 FAIL Registering script with good MIME type text/livescript promise_test: Unhandled rejection with value: object "[object Event]"
-PASS Registering script that imports script with good MIME type text/livescript 
+PASS Registering script that imports script with good MIME type text/livescript
 FAIL Registering script with good MIME type text/x-ecmascript promise_test: Unhandled rejection with value: object "[object Event]"
-PASS Registering script that imports script with good MIME type text/x-ecmascript 
+PASS Registering script that imports script with good MIME type text/x-ecmascript
 FAIL Registering script with good MIME type text/x-javascript promise_test: Unhandled rejection with value: object "[object Event]"
-PASS Registering script that imports script with good MIME type text/x-javascript 
+PASS Registering script that imports script with good MIME type text/x-javascript
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/link-element-register-scope.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/link-element-register-scope.https-expected.txt
index ccd4b54..c2ebe84 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/link-element-register-scope.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/link-element-register-scope.https-expected.txt
@@ -1,11 +1,11 @@
 This is a testharness.js-based test.
 FAIL Scope including URL-encoded slash Test bug: need to pass exception to assert_throws()
 FAIL Scope including URL-encoded backslash Test bug: need to pass exception to assert_throws()
-PASS Scope including URL-encoded multibyte characters 
-PASS Scope including non-escaped multibyte characters 
-PASS Scope including self-reference 
-PASS Scope including parent-reference 
-PASS Scope including consecutive slashes 
+PASS Scope including URL-encoded multibyte characters
+PASS Scope including non-escaped multibyte characters
+PASS Scope including self-reference
+PASS Scope including parent-reference
+PASS Scope including consecutive slashes
 FAIL Scope URL is same-origin filesystem: URL Test bug: need to pass exception to assert_throws()
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/link-element-register-script-url.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/link-element-register-script-url.https-expected.txt
index f2813c0..ce29087 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/link-element-register-script-url.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/link-element-register-script-url.https-expected.txt
@@ -3,7 +3,7 @@
 FAIL Script URL including uppercase URL-encoded slash Test bug: need to pass exception to assert_throws()
 FAIL Script URL including URL-encoded backslash Test bug: need to pass exception to assert_throws()
 FAIL Script URL including uppercase URL-encoded backslash Test bug: need to pass exception to assert_throws()
-PASS Script URL including self-reference 
-PASS Script URL including parent-reference 
+PASS Script URL including self-reference
+PASS Script URL including parent-reference
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/link-element-register-script.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/link-element-register-script.https-expected.txt
index 52dc9248..1dbf650 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/link-element-register-script.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/link-element-register-script.https-expected.txt
@@ -7,6 +7,6 @@
 FAIL Registering script importing malformed script Test bug: need to pass exception to assert_throws()
 FAIL Registering non-existent script Test bug: need to pass exception to assert_throws()
 FAIL Registering script importing non-existent script Test bug: need to pass exception to assert_throws()
-PASS Registering script including caught exception 
+PASS Registering script including caught exception
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/link-element-register-security-error.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/link-element-register-security-error.https-expected.txt
index 78c5360..742add3 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/link-element-register-security-error.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/link-element-register-security-error.https-expected.txt
@@ -1,11 +1,11 @@
 This is a testharness.js-based test.
-FAIL Registering same scope as the script directory without the last slash Test bug: need to pass exception to assert_throws()
-FAIL Registration scope outside the script directory Test bug: need to pass exception to assert_throws()
-FAIL Registering scope outside domain Test bug: need to pass exception to assert_throws()
-FAIL Registering script outside domain Test bug: need to pass exception to assert_throws()
-FAIL Registering redirected script Test bug: need to pass exception to assert_throws()
-FAIL Scope including parent-reference and not under the script directory Test bug: need to pass exception to assert_throws()
-FAIL Script URL including consecutive slashes Test bug: need to pass exception to assert_throws()
-FAIL Script URL is same-origin filesystem: URL Test bug: need to pass exception to assert_throws()
+FAIL Registering same scope as the script directory without the last slashTest bug: need to pass exception to assert_throws()
+FAIL Registration scope outside the script directoryTest bug: need to pass exception to assert_throws()
+FAIL Registering scope outside domainTest bug: need to pass exception to assert_throws()
+FAIL Registering script outside domainTest bug: need to pass exception to assert_throws()
+FAIL Registering redirected scriptTest bug: need to pass exception to assert_throws()
+FAIL Scope including parent-reference and not under the script directoryTest bug: need to pass exception to assert_throws()
+FAIL Script URL including consecutive slashesTest bug: need to pass exception to assert_throws()
+FAIL Script URL is same-origin filesystem: URLTest bug: need to pass exception to assert_throws()
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/registration-mime-types.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/registration-mime-types.https-expected.txt
index 1fb8416..e4d2ccd0 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/registration-mime-types.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/registration-mime-types.https-expected.txt
@@ -1,39 +1,39 @@
 This is a testharness.js-based test.
-PASS Registering script with no MIME type 
-PASS Registering script with bad MIME type 
+PASS Registering script with no MIME type
+PASS Registering script with bad MIME type
 FAIL Registering script that imports script with no MIME type assert_unreached: Should have rejected: Registration of no MIME type imported script should fail. Reached unreachable code
 FAIL Registering script that imports script with bad MIME type assert_unreached: Should have rejected: Registration of plain text imported script should fail. Reached unreachable code
 FAIL Registering script with good MIME type application/ecmascript promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('application/ecmascript')."
-PASS Registering script that imports script with good MIME type application/ecmascript 
-PASS Registering script with good MIME type application/javascript 
-PASS Registering script that imports script with good MIME type application/javascript 
+PASS Registering script that imports script with good MIME type application/ecmascript
+PASS Registering script with good MIME type application/javascript
+PASS Registering script that imports script with good MIME type application/javascript
 FAIL Registering script with good MIME type application/x-ecmascript promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('application/x-ecmascript')."
-PASS Registering script that imports script with good MIME type application/x-ecmascript 
-PASS Registering script with good MIME type application/x-javascript 
-PASS Registering script that imports script with good MIME type application/x-javascript 
+PASS Registering script that imports script with good MIME type application/x-ecmascript
+PASS Registering script with good MIME type application/x-javascript
+PASS Registering script that imports script with good MIME type application/x-javascript
 FAIL Registering script with good MIME type text/ecmascript promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/ecmascript')."
-PASS Registering script that imports script with good MIME type text/ecmascript 
-PASS Registering script with good MIME type text/javascript 
-PASS Registering script that imports script with good MIME type text/javascript 
+PASS Registering script that imports script with good MIME type text/ecmascript
+PASS Registering script with good MIME type text/javascript
+PASS Registering script that imports script with good MIME type text/javascript
 FAIL Registering script with good MIME type text/javascript1.0 promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/javascript1.0')."
-PASS Registering script that imports script with good MIME type text/javascript1.0 
+PASS Registering script that imports script with good MIME type text/javascript1.0
 FAIL Registering script with good MIME type text/javascript1.1 promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/javascript1.1')."
-PASS Registering script that imports script with good MIME type text/javascript1.1 
+PASS Registering script that imports script with good MIME type text/javascript1.1
 FAIL Registering script with good MIME type text/javascript1.2 promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/javascript1.2')."
-PASS Registering script that imports script with good MIME type text/javascript1.2 
+PASS Registering script that imports script with good MIME type text/javascript1.2
 FAIL Registering script with good MIME type text/javascript1.3 promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/javascript1.3')."
-PASS Registering script that imports script with good MIME type text/javascript1.3 
+PASS Registering script that imports script with good MIME type text/javascript1.3
 FAIL Registering script with good MIME type text/javascript1.4 promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/javascript1.4')."
-PASS Registering script that imports script with good MIME type text/javascript1.4 
+PASS Registering script that imports script with good MIME type text/javascript1.4
 FAIL Registering script with good MIME type text/javascript1.5 promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/javascript1.5')."
-PASS Registering script that imports script with good MIME type text/javascript1.5 
+PASS Registering script that imports script with good MIME type text/javascript1.5
 FAIL Registering script with good MIME type text/jscript promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/jscript')."
-PASS Registering script that imports script with good MIME type text/jscript 
+PASS Registering script that imports script with good MIME type text/jscript
 FAIL Registering script with good MIME type text/livescript promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/livescript')."
-PASS Registering script that imports script with good MIME type text/livescript 
+PASS Registering script that imports script with good MIME type text/livescript
 FAIL Registering script with good MIME type text/x-ecmascript promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/x-ecmascript')."
-PASS Registering script that imports script with good MIME type text/x-ecmascript 
+PASS Registering script that imports script with good MIME type text/x-ecmascript
 FAIL Registering script with good MIME type text/x-javascript promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/x-javascript')."
-PASS Registering script that imports script with good MIME type text/x-javascript 
+PASS Registering script that imports script with good MIME type text/x-javascript
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/byte-length-queuing-strategy.js b/third_party/WebKit/LayoutTests/external/wpt/streams/byte-length-queuing-strategy.js
index 54407af..e96e68ee 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/streams/byte-length-queuing-strategy.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/byte-length-queuing-strategy.js
@@ -104,4 +104,11 @@
 
 }, 'ByteLengthQueuingStrategy\'s highWaterMark property can be set to anything');
 
+test(() => {
+
+  assert_equals(ByteLengthQueuingStrategy.name, 'ByteLengthQueuingStrategy',
+                'ByteLengthQueuingStrategy.name must be "ByteLengthQueuingStrategy"');
+
+}, 'ByteLengthQueuingStrategy.name is correct');
+
 done();
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/count-queuing-strategy.js b/third_party/WebKit/LayoutTests/external/wpt/streams/count-queuing-strategy.js
index 5ae0063..8da8eb6 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/streams/count-queuing-strategy.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/count-queuing-strategy.js
@@ -103,4 +103,11 @@
 
 }, 'CountQueuingStrategy\'s highWaterMark property can be set to anything');
 
+test(() => {
+
+  assert_equals(CountQueuingStrategy.name, 'CountQueuingStrategy',
+                'CountQueuingStrategy.name must be "CountQueuingStrategy"');
+
+}, 'CountQueuingStrategy.name is correct');
+
 done();
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/properties-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/properties-expected.txt
new file mode 100644
index 0000000..83c737b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/properties-expected.txt
@@ -0,0 +1,8 @@
+This is a testharness.js-based test.
+FAIL Can get the ReadableStreamBYOBReader constructor indirectly bytes type is not yet implemented
+PASS ReadableStreamBYOBReader constructor should get a ReadableStream object as argument
+FAIL ReadableStreamBYOBReader instances should have the correct list of properties bytes type is not yet implemented
+FAIL ReadableStreamBYOBRequest instances should have the correct list of properties bytes type is not yet implemented
+FAIL ReadableByteStreamController instances should have the correct list of properties bytes type is not yet implemented
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/properties.dedicatedworker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/properties.dedicatedworker-expected.txt
new file mode 100644
index 0000000..83c737b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/properties.dedicatedworker-expected.txt
@@ -0,0 +1,8 @@
+This is a testharness.js-based test.
+FAIL Can get the ReadableStreamBYOBReader constructor indirectly bytes type is not yet implemented
+PASS ReadableStreamBYOBReader constructor should get a ReadableStream object as argument
+FAIL ReadableStreamBYOBReader instances should have the correct list of properties bytes type is not yet implemented
+FAIL ReadableStreamBYOBRequest instances should have the correct list of properties bytes type is not yet implemented
+FAIL ReadableByteStreamController instances should have the correct list of properties bytes type is not yet implemented
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/properties.dedicatedworker.html b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/properties.dedicatedworker.html
new file mode 100644
index 0000000..50d63ed
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/properties.dedicatedworker.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>properties.js dedicated worker wrapper file</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+'use strict';
+fetch_tests_from_worker(new Worker('properties.js'));
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/properties.html b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/properties.html
new file mode 100644
index 0000000..41ab6b2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/properties.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>properties.js browser context wrapper file</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script src="../resources/rs-utils.js"></script>
+
+<script src="properties.js"></script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/properties.js b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/properties.js
new file mode 100644
index 0000000..21549bc6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/properties.js
@@ -0,0 +1,147 @@
+'use strict';
+
+if (self.importScripts) {
+  self.importScripts('../resources/rs-utils.js');
+  self.importScripts('/resources/testharness.js');
+}
+
+let ReadableStreamBYOBReader;
+
+test(() => {
+
+  // It's not exposed globally, but we test a few of its properties here.
+  ReadableStreamBYOBReader = (new ReadableStream({ type: 'bytes' }))
+      .getReader({ mode: 'byob' }).constructor;
+
+}, 'Can get the ReadableStreamBYOBReader constructor indirectly');
+
+test(() => {
+
+  assert_throws(new TypeError(), () => new ReadableStreamBYOBReader('potato'));
+  assert_throws(new TypeError(), () => new ReadableStreamBYOBReader({}));
+  assert_throws(new TypeError(), () => new ReadableStreamBYOBReader());
+
+}, 'ReadableStreamBYOBReader constructor should get a ReadableStream object as argument');
+
+test(() => {
+
+  const methods = ['cancel', 'constructor', 'read', 'releaseLock'];
+  const properties = methods.concat(['closed']).sort();
+
+  const rsReader = new ReadableStreamBYOBReader(new ReadableStream({ type: 'bytes' }));
+  const proto = Object.getPrototypeOf(rsReader);
+
+  assert_array_equals(Object.getOwnPropertyNames(proto).sort(), properties);
+
+  for (const m of methods) {
+    const propDesc = Object.getOwnPropertyDescriptor(proto, m);
+    assert_equals(propDesc.enumerable, false, 'method should be non-enumerable');
+    assert_equals(propDesc.configurable, true, 'method should be configurable');
+    assert_equals(propDesc.writable, true, 'method should be writable');
+    assert_equals(typeof rsReader[m], 'function', 'should have be a method');
+    const expectedName = m === 'constructor' ? 'ReadableStreamBYOBReader' : m;
+    assert_equals(rsReader[m].name, expectedName, 'method should have the correct name');
+  }
+
+  const closedPropDesc = Object.getOwnPropertyDescriptor(proto, 'closed');
+  assert_equals(closedPropDesc.enumerable, false, 'closed should be non-enumerable');
+  assert_equals(closedPropDesc.configurable, true, 'closed should be configurable');
+  assert_not_equals(closedPropDesc.get, undefined, 'closed should have a getter');
+  assert_equals(closedPropDesc.set, undefined, 'closed should not have a setter');
+
+  assert_equals(rsReader.cancel.length, 1, 'cancel has 1 parameter');
+  assert_not_equals(rsReader.closed, undefined, 'has a non-undefined closed property');
+  assert_equals(typeof rsReader.closed.then, 'function', 'closed property is thenable');
+  assert_equals(rsReader.constructor.length, 1, 'constructor has 1 parameter');
+  assert_equals(rsReader.read.length, 1, 'read has 1 parameter');
+  assert_equals(rsReader.releaseLock.length, 0, 'releaseLock has no parameters');
+
+}, 'ReadableStreamBYOBReader instances should have the correct list of properties');
+
+promise_test(t => {
+
+  const rs = new ReadableStream({
+    pull(controller) {
+      return t.step(() => {
+        const byobRequest = controller.byobRequest;
+
+        const methods = ['constructor', 'respond', 'respondWithNewView'];
+        const properties = methods.concat(['view']).sort();
+
+        const proto = Object.getPrototypeOf(byobRequest);
+
+        assert_array_equals(Object.getOwnPropertyNames(proto).sort(), properties);
+
+        for (const m of methods) {
+          const propDesc = Object.getOwnPropertyDescriptor(proto, m);
+          assert_equals(propDesc.enumerable, false, 'method should be non-enumerable');
+          assert_equals(propDesc.configurable, true, 'method should be configurable');
+          assert_equals(propDesc.writable, true, 'method should be writable');
+          assert_equals(typeof byobRequest[m], 'function', 'should have a method');
+          const expectedName = m === 'constructor' ? 'ReadableStreamBYOBRequest' : m;
+          assert_equals(byobRequest[m].name, expectedName, 'method should have the correct name');
+        }
+
+        const viewPropDesc = Object.getOwnPropertyDescriptor(proto, 'view');
+        assert_equals(viewPropDesc.enumerable, false, 'view should be non-enumerable');
+        assert_equals(viewPropDesc.configurable, true, 'view should be configurable');
+        assert_not_equals(viewPropDesc.get, undefined, 'view should have a getter');
+        assert_equals(viewPropDesc.set, undefined, 'view should not have a setter');
+        assert_not_equals(byobRequest.view, undefined, 'has a non-undefined view property');
+        assert_equals(byobRequest.constructor.length, 2, 'constructor has 1 parameter');
+        assert_equals(byobRequest.respond.length, 1, 'respond has 1 parameter');
+        assert_equals(byobRequest.respondWithNewView.length, 1, 'releaseLock has 1 parameter');
+
+        byobRequest.respond(1);
+
+      });
+    },
+    type: 'bytes' });
+  const reader = rs.getReader({ mode: 'byob' });
+  return reader.read(new Uint8Array(1));
+
+}, 'ReadableStreamBYOBRequest instances should have the correct list of properties');
+
+test(() => {
+
+  const methods = ['close', 'constructor', 'enqueue', 'error'];
+  const accessors = ['byobRequest', 'desiredSize'];
+  const properties = methods.concat(accessors).sort();
+
+  let controller;
+  new ReadableStream({
+    start(c) {
+      controller = c;
+    },
+    type: 'bytes'
+  });
+  const proto = Object.getPrototypeOf(controller);
+
+  assert_array_equals(Object.getOwnPropertyNames(proto).sort(), properties);
+
+  for (const m of methods) {
+    const propDesc = Object.getOwnPropertyDescriptor(proto, m);
+    assert_equals(propDesc.enumerable, false, 'method should be non-enumerable');
+    assert_equals(propDesc.configurable, true, 'method should be configurable');
+    assert_equals(propDesc.writable, true, 'method should be writable');
+    assert_equals(typeof controller[m], 'function', 'should have be a method');
+    const expectedName = m === 'constructor' ? 'ReadableByteStreamController' : m;
+    assert_equals(controller[m].name, expectedName, 'method should have the correct name');
+  }
+
+  for (const a of accessors) {
+    const propDesc = Object.getOwnPropertyDescriptor(proto, a);
+    assert_equals(propDesc.enumerable, false, `${a} should be non-enumerable`);
+    assert_equals(propDesc.configurable, true, `${a} should be configurable`);
+    assert_not_equals(propDesc.get, undefined, `${a} should have a getter`);
+    assert_equals(propDesc.set, undefined, `${a} should not have a setter`);
+  }
+
+  assert_equals(controller.close.length, 0, 'cancel has no parameters');
+  assert_equals(controller.constructor.length, 3, 'constructor has 3 parameters');
+  assert_equals(controller.enqueue.length, 1, 'enqueue has 1 parameter');
+  assert_equals(controller.error.length, 1, 'releaseLock has 1 parameter');
+
+}, 'ReadableByteStreamController instances should have the correct list of properties');
+
+done();
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/properties.serviceworker.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/properties.serviceworker.https-expected.txt
new file mode 100644
index 0000000..abf808a8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/properties.serviceworker.https-expected.txt
@@ -0,0 +1,9 @@
+This is a testharness.js-based test.
+PASS Service worker test setup
+FAIL Can get the ReadableStreamBYOBReader constructor indirectly bytes type is not yet implemented
+PASS ReadableStreamBYOBReader constructor should get a ReadableStream object as argument
+FAIL ReadableStreamBYOBReader instances should have the correct list of properties bytes type is not yet implemented
+FAIL ReadableStreamBYOBRequest instances should have the correct list of properties bytes type is not yet implemented
+FAIL ReadableByteStreamController instances should have the correct list of properties bytes type is not yet implemented
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/properties.serviceworker.https.html b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/properties.serviceworker.https.html
new file mode 100644
index 0000000..ba5c5135
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/properties.serviceworker.https.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>properties.js service worker wrapper file</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script>
+
+<script>
+'use strict';
+service_worker_test('properties.js', 'Service worker test setup');
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/properties.sharedworker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/properties.sharedworker-expected.txt
new file mode 100644
index 0000000..83c737b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/properties.sharedworker-expected.txt
@@ -0,0 +1,8 @@
+This is a testharness.js-based test.
+FAIL Can get the ReadableStreamBYOBReader constructor indirectly bytes type is not yet implemented
+PASS ReadableStreamBYOBReader constructor should get a ReadableStream object as argument
+FAIL ReadableStreamBYOBReader instances should have the correct list of properties bytes type is not yet implemented
+FAIL ReadableStreamBYOBRequest instances should have the correct list of properties bytes type is not yet implemented
+FAIL ReadableByteStreamController instances should have the correct list of properties bytes type is not yet implemented
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/properties.sharedworker.html b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/properties.sharedworker.html
new file mode 100644
index 0000000..42fb3e5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/properties.sharedworker.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>properties.js shared worker wrapper file</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+'use strict';
+fetch_tests_from_worker(new SharedWorker('properties.js'));
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/readable-streams/default-reader.js b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-streams/default-reader.js
index 1a5d3a4..7543545c 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/streams/readable-streams/default-reader.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-streams/default-reader.js
@@ -38,6 +38,8 @@
     assert_equals(propDesc.configurable, true, 'method should be configurable');
     assert_equals(propDesc.writable, true, 'method should be writable');
     assert_equals(typeof rsReader[m], 'function', 'should have be a method');
+    const expectedName = m === 'constructor' ? 'ReadableStreamDefaultReader' : m;
+    assert_equals(rsReader[m].name, expectedName, 'method should have the correct name');
   }
 
   const closedPropDesc = Object.getOwnPropertyDescriptor(proto, 'closed');
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/readable-streams/general.js b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-streams/general.js
index 472fb4b..5150c36 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/streams/readable-streams/general.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-streams/general.js
@@ -56,6 +56,8 @@
     assert_true(propDesc.configurable, 'method should be configurable');
     assert_true(propDesc.writable, 'method should be writable');
     assert_equals(typeof rs[m], 'function', 'method should be a function');
+    const expectedName = m === 'constructor' ? 'ReadableStream' : m;
+    assert_equals(rs[m].name, expectedName, 'method should have the correct name');
   }
 
   const lockedPropDesc = Object.getOwnPropertyDescriptor(proto, 'locked');
@@ -115,6 +117,8 @@
         assert_false(propDesc.enumerable, m + ' should be non-enumerable');
         assert_true(propDesc.configurable, m + ' should be configurable');
         assert_true(propDesc.writable, m + ' should be writable');
+        const expectedName = m === 'constructor' ? 'ReadableStreamDefaultController' : m;
+        assert_equals(controller[m].name, expectedName, 'method should have the correct name');
       }
 
       const desiredSizePropDesc = Object.getOwnPropertyDescriptor(proto, 'desiredSize');
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/writable-streams/properties.js b/third_party/WebKit/LayoutTests/external/wpt/streams/writable-streams/properties.js
index 6ccb1a2..99bd09a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/streams/writable-streams/properties.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/writable-streams/properties.js
@@ -127,8 +127,10 @@
                         `${name} should take ${properties[name].length} arguments`);
           if (type === 'constructor') {
             assert_true(IsConstructor(prototype[name]), `${name} should be a constructor`);
+            assert_equals(prototype[name].name, c, `${name}.name should be '${c}'`);
           } else {
             assert_false(IsConstructor(prototype[name]), `${name} should not be a constructor`);
+            assert_equals(prototype[name].name, name, `${name}.name should be '${name}`);
           }
         }, `${fullName} should be a ${type}`);
         break;
diff --git a/third_party/WebKit/LayoutTests/external/wpt/wasm/many-memories.window.js b/third_party/WebKit/LayoutTests/external/wpt/wasm/many-memories.window.js
new file mode 100644
index 0000000..0613a00
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/wasm/many-memories.window.js
@@ -0,0 +1,19 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This test makes sure browsers behave reasonably when asked to allocate a
+// large number of WebAssembly.Memory objects at once.
+test(function() {
+  let memories = [];
+  try {
+    for (let i = 0; i < 600; i++) {
+      memories.push(new WebAssembly.Memory({initial: 1}));
+    }
+  } catch (e) {
+    if (e instanceof RangeError) {
+      return;
+    }
+    throw e;
+  }
+}, "WebAssembly#CreateManyMemories");
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webusb/usb-allowed-by-feature-policy.https.sub.html.headers b/third_party/WebKit/LayoutTests/external/wpt/webusb/usb-allowed-by-feature-policy.https.sub.html.headers
index f10a282c..5c7eac0 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webusb/usb-allowed-by-feature-policy.https.sub.html.headers
+++ b/third_party/WebKit/LayoutTests/external/wpt/webusb/usb-allowed-by-feature-policy.https.sub.html.headers
@@ -1 +1 @@
-Feature-Policy: {"usb": ["*"]}
+Feature-Policy: usb *
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webusb/usb-disabled-by-feature-policy.https.sub.html.headers b/third_party/WebKit/LayoutTests/external/wpt/webusb/usb-disabled-by-feature-policy.https.sub.html.headers
index 24332c7..4fd1e269 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webusb/usb-disabled-by-feature-policy.https.sub.html.headers
+++ b/third_party/WebKit/LayoutTests/external/wpt/webusb/usb-disabled-by-feature-policy.https.sub.html.headers
@@ -1 +1 @@
-Feature-Policy: {"usb": []}
+Feature-Policy: usb 'none'
diff --git a/third_party/WebKit/LayoutTests/fast/borders/overflow-hidden-border-radius-force-backing-store-expected.txt b/third_party/WebKit/LayoutTests/fast/borders/overflow-hidden-border-radius-force-backing-store-expected.txt
index 1825e208..eb82c478b 100644
--- a/third_party/WebKit/LayoutTests/fast/borders/overflow-hidden-border-radius-force-backing-store-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/borders/overflow-hidden-border-radius-force-backing-store-expected.txt
@@ -14,6 +14,7 @@
     },
     {
       "name": "Child Containment Layer",
+      "position": [50, 50],
       "bounds": [300, 300],
       "maskLayer": [
         {
@@ -25,11 +26,12 @@
     },
     {
       "name": "Ancestor Clipping Layer",
-      "bounds": [285, 300],
-      "shouldFlattenTransform": false
+      "position": [50, 50],
+      "bounds": [285, 300]
     },
     {
       "name": "LayoutBlockFlow DIV id='content'",
+      "position": [50, 50],
       "bounds": [285, 1000],
       "contentsOpaque": true,
       "drawsContent": true
diff --git a/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-listing-expected.txt b/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-listing-expected.txt
index 72aa260..fe529f24 100644
--- a/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-listing-expected.txt
@@ -48,7 +48,7 @@
 -webkit-text-combine: none
 -webkit-text-decorations-in-effect: none
 -webkit-text-emphasis-color: rgb(0, 0, 0)
--webkit-text-emphasis-position: over
+-webkit-text-emphasis-position: over right
 -webkit-text-emphasis-style: none
 -webkit-text-fill-color: rgb(0, 0, 0)
 -webkit-text-orientation: vertical-right
diff --git a/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-without-renderer-listing-expected.txt b/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-without-renderer-listing-expected.txt
index 0fa043b..20728d9fc 100644
--- a/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-without-renderer-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-without-renderer-listing-expected.txt
@@ -48,7 +48,7 @@
 -webkit-text-combine: none
 -webkit-text-decorations-in-effect: none
 -webkit-text-emphasis-color: rgb(0, 0, 0)
--webkit-text-emphasis-position: over
+-webkit-text-emphasis-position: over right
 -webkit-text-emphasis-style: none
 -webkit-text-fill-color: rgb(0, 0, 0)
 -webkit-text-orientation: vertical-right
diff --git a/third_party/WebKit/LayoutTests/fast/css/parsing-text-emphasis-expected.txt b/third_party/WebKit/LayoutTests/fast/css/parsing-text-emphasis-expected.txt
index 434059c..baa628c6 100644
--- a/third_party/WebKit/LayoutTests/fast/css/parsing-text-emphasis-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/css/parsing-text-emphasis-expected.txt
@@ -8,8 +8,22 @@
 
 PASS: '-webkit-text-emphasis-position: initial;' parsed as ['', 'initial', '', '']
 PASS: '-webkit-text-emphasis-position: inherit;' parsed as ['', 'inherit', '', '']
-PASS: '-webkit-text-emphasis-position: over;' parsed as ['', 'over', '', '']
-PASS: '-webkit-text-emphasis-position: under;' parsed as ['', 'under', '', '']
+PASS: '-webkit-text-emphasis-position: over;' parsed as ['', 'over right', '', '']
+PASS: '-webkit-text-emphasis-position: over right;' parsed as ['', 'over right', '', '']
+PASS: '-webkit-text-emphasis-position: right over;' parsed as ['', 'over right', '', '']
+PASS: '-webkit-text-emphasis-position: over left;' parsed as ['', 'over left', '', '']
+PASS: '-webkit-text-emphasis-position: left over;' parsed as ['', 'over left', '', '']
+PASS: '-webkit-text-emphasis-position: under;' parsed as ['', 'under right', '', '']
+PASS: '-webkit-text-emphasis-position: under right;' parsed as ['', 'under right', '', '']
+PASS: '-webkit-text-emphasis-position: right under;' parsed as ['', 'under right', '', '']
+PASS: '-webkit-text-emphasis-position: under left;' parsed as ['', 'under left', '', '']
+PASS: '-webkit-text-emphasis-position: left under;' parsed as ['', 'under left', '', '']
+PASS: '-webkit-text-emphasis-position: over under;' parsed as ['', '', '', '']
+PASS: '-webkit-text-emphasis-position: under over;' parsed as ['', '', '', '']
+PASS: '-webkit-text-emphasis-position: left;' parsed as ['', '', '', '']
+PASS: '-webkit-text-emphasis-position: right;' parsed as ['', '', '', '']
+PASS: '-webkit-text-emphasis-position: left right;' parsed as ['', '', '', '']
+PASS: '-webkit-text-emphasis-position: right left;' parsed as ['', '', '', '']
 PASS: '-webkit-text-emphasis-position: bold;' parsed as ['', '', '', '']
 PASS: '-webkit-text-emphasis-position: 1px;' parsed as ['', '', '', '']
 PASS: '-webkit-text-emphasis-position: "over";' parsed as ['', '', '', '']
diff --git a/third_party/WebKit/LayoutTests/fast/css/parsing-text-emphasis.html b/third_party/WebKit/LayoutTests/fast/css/parsing-text-emphasis.html
index 58d1311e..4bab566 100644
--- a/third_party/WebKit/LayoutTests/fast/css/parsing-text-emphasis.html
+++ b/third_party/WebKit/LayoutTests/fast/css/parsing-text-emphasis.html
@@ -36,8 +36,22 @@
     log("");
     test('-webkit-text-emphasis-position: initial;', '', 'initial', '');
     test('-webkit-text-emphasis-position: inherit;', '', 'inherit', '');
-    test('-webkit-text-emphasis-position: over;', '', 'over', '');
-    test('-webkit-text-emphasis-position: under;', '', 'under', '');
+    test('-webkit-text-emphasis-position: over;', '', 'over right', '');
+    test('-webkit-text-emphasis-position: over right;', '', 'over right', '');
+    test('-webkit-text-emphasis-position: right over;', '', 'over right', '');
+    test('-webkit-text-emphasis-position: over left;', '', 'over left', '');
+    test('-webkit-text-emphasis-position: left over;', '', 'over left', '');
+    test('-webkit-text-emphasis-position: under;', '', 'under right', '');
+    test('-webkit-text-emphasis-position: under right;', '', 'under right', '');
+    test('-webkit-text-emphasis-position: right under;', '', 'under right', '');
+    test('-webkit-text-emphasis-position: under left;', '', 'under left', '');
+    test('-webkit-text-emphasis-position: left under;', '', 'under left', '');
+    test('-webkit-text-emphasis-position: over under;', '', '', '');
+    test('-webkit-text-emphasis-position: under over;', '', '', '');
+    test('-webkit-text-emphasis-position: left;', '', '', '');
+    test('-webkit-text-emphasis-position: right;', '', '', '');
+    test('-webkit-text-emphasis-position: left right;', '', '', '');
+    test('-webkit-text-emphasis-position: right left;', '', '', '');
     test('-webkit-text-emphasis-position: bold;', '', '', '');
     test('-webkit-text-emphasis-position: 1px;', '', '', '');
     test('-webkit-text-emphasis-position: "over";', '', '', '');
diff --git a/third_party/WebKit/LayoutTests/fast/loader/object-with-rejected-resource.html b/third_party/WebKit/LayoutTests/fast/loader/object-with-rejected-resource.html
index 5156774dd..42bbe464 100644
--- a/third_party/WebKit/LayoutTests/fast/loader/object-with-rejected-resource.html
+++ b/third_party/WebKit/LayoutTests/fast/loader/object-with-rejected-resource.html
@@ -7,6 +7,6 @@
   testRunner.dumpAsText();
 }
 </script>
-<object data="http://funky@town/will_be_blocked.txt">
+<object data="http://funky@town.test/will_be_blocked.txt">
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/fast/table/table-cell-colspan-exceeds-total-cols-crash.html b/third_party/WebKit/LayoutTests/fast/table/table-cell-colspan-exceeds-total-cols-crash.html
new file mode 100644
index 0000000..32d73aa
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/table/table-cell-colspan-exceeds-total-cols-crash.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<table>
+    <colgroup style="visibility:collapse"></colgroup>
+    <td></td>
+    <td colspan="2"></td>
+</table>
+<script>
+    test(() => {
+    }, "No crash or assertion failure. crbug.com/758503");
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/text/emphasis-avoid-ruby.html b/third_party/WebKit/LayoutTests/fast/text/emphasis-avoid-ruby.html
index dbae53f..afd5f387 100644
--- a/third_party/WebKit/LayoutTests/fast/text/emphasis-avoid-ruby.html
+++ b/third_party/WebKit/LayoutTests/fast/text/emphasis-avoid-ruby.html
@@ -20,15 +20,15 @@
 
     <!-- emphasis under, should not be suppressed by ruby -->
     <div class="flipped">
-        1 <ruby><rb>23 <span style="-webkit-text-emphasis-position: under;">45</span></rb><rt>678</rt></ruby>
+        1 <ruby><rb>23 <span style="-webkit-text-emphasis-position: under left;">45</span></rb><rt>678</rt></ruby>
     </div>
     <!-- emphasis over, but no lines in ruby text, should not inhibit emphasis -->
     <div class="flipped">
-        1 <ruby><rb>23 <span style="-webkit-text-emphasis-position: over;">45</span></rb><rt> </rt></ruby>
+        1 <ruby><rb>23 <span style="-webkit-text-emphasis-position: over right;">45</span></rb><rt> </rt></ruby>
     </div>
     <!-- emphasis over should be suppressed by ruby -->
     <div class="flipped">
-        1 <ruby><rb>23 <span style="-webkit-text-emphasis-position: over; -webkit-text-emphasis-color: red;">45</span></rb><rt>678</rt></ruby>
+        1 <ruby><rb>23 <span style="-webkit-text-emphasis-position: over right; -webkit-text-emphasis-color: red;">45</span></rb><rt>678</rt></ruby>
     </div>
 
 </body>
diff --git a/third_party/WebKit/LayoutTests/fast/text/emphasis-overlap.html b/third_party/WebKit/LayoutTests/fast/text/emphasis-overlap.html
index 78f5b55..0ea01572 100644
--- a/third_party/WebKit/LayoutTests/fast/text/emphasis-overlap.html
+++ b/third_party/WebKit/LayoutTests/fast/text/emphasis-overlap.html
@@ -3,8 +3,8 @@
     div div { font-family: Ahem; font-size: 32px; -webkit-font-smoothing: none; display: inline-block; margin: 8px 0; }
     .flipped { writing-mode: vertical-rl; }
     div.flipped div { display: block; margin:0 8px 0 0; }
-    .over { color: blue; -webkit-text-emphasis: "m"; -webkit-text-emphasis-position: over; }
-    .under { color: green; -webkit-text-emphasis: "m"; -webkit-text-emphasis-position: under; }
+    .over { color: blue; -webkit-text-emphasis: "m"; -webkit-text-emphasis-position: over right; }
+    .under { color: green; -webkit-text-emphasis: "m"; -webkit-text-emphasis-position: under left; }
 </style>
 <div>
     <div>
diff --git a/third_party/WebKit/LayoutTests/fast/text/emphasis-vertical.html b/third_party/WebKit/LayoutTests/fast/text/emphasis-vertical.html
index e7f0609..29724fc2 100644
--- a/third_party/WebKit/LayoutTests/fast/text/emphasis-vertical.html
+++ b/third_party/WebKit/LayoutTests/fast/text/emphasis-vertical.html
@@ -18,7 +18,7 @@
 </style>
 
 <div>
-    せっかく見つけたすばらしい記事<span style="-webkit-text-emphasis: '@';">がどこにあったか忘れてしま</span>った経験はありますか<span style="-webkit-text-emphasis: '*'; -webkit-text-emphasis-position: under;">ならタイトルとアドレスだけでなく、</span>訪問したウェブページのコンテンツからも検索することができます。
+    せっかく見つけたすばらしい記事<span style="-webkit-text-emphasis: '@';">がどこにあったか忘れてしま</span>った経験はありますか<span style="-webkit-text-emphasis: '*'; -webkit-text-emphasis-position: under left;">ならタイトルとアドレスだけでなく、</span>訪問したウェブページのコンテンツからも検索することができます。
 </div>
 
 <div>
@@ -30,5 +30,5 @@
 </div>
 
 <div style="line-height: 2;">
-    せっかく見つけたすばらしい記事<span style="-webkit-text-emphasis: filled;">がどこにあったか忘れてしま</span>った経験はありますか<span style="-webkit-text-emphasis: open; -webkit-text-emphasis-position: under;">ならタイトルとアドレスだけでなく、</span>訪問したウェブページのコンテンツからも検索することができます。
+    せっかく見つけたすばらしい記事<span style="-webkit-text-emphasis: filled;">がどこにあったか忘れてしま</span>った経験はありますか<span style="-webkit-text-emphasis: open; -webkit-text-emphasis-position: under left;">ならタイトルとアドレスだけでなく、</span>訪問したウェブページのコンテンツからも検索することができます。
 </div>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-expected.txt
index 99da3d48..c7fae3e2 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-format-expected.txt
@@ -263,10 +263,10 @@
 console-format.html:8 [Number]
 globals[32]
 Number {[[PrimitiveValue]]: 42}
-console-format.html:7 String {[[PrimitiveValue]]: "abc"}
+console-format.html:7 String {0: "a", 1: "b", 2: "c", length: 3, [[PrimitiveValue]]: "abc"}
 console-format.html:8 [String]
 globals[33]
-String {[[PrimitiveValue]]: "abc"}
+String {0: "a", 1: "b", 2: "c", length: 3, [[PrimitiveValue]]: "abc"}
 console-format.html:7 Uint16Array(3) [1, 2, 3]
 console-format.html:8 [Uint16Array(3)]
 globals[34]
@@ -661,7 +661,7 @@
 Number {[[PrimitiveValue]]: 42}
     __proto__: Number
     [[PrimitiveValue]]: 42
-console-format.html:7 String {[[PrimitiveValue]]: "abc"}
+console-format.html:7 String {0: "a", 1: "b", 2: "c", length: 3, [[PrimitiveValue]]: "abc"}
     0: "a"
     1: "b"
     2: "c"
@@ -669,11 +669,11 @@
     __proto__: String
     [[PrimitiveValue]]: "abc"
 console-format.html:8 [String]
-    0: String {[[PrimitiveValue]]: "abc"}
+    0: String {0: "a", 1: "b", 2: "c", length: 3, [[PrimitiveValue]]: "abc"}
     length: 1
     __proto__: Array(0)
 globals[33]
-String {[[PrimitiveValue]]: "abc"}
+String {0: "a", 1: "b", 2: "c", length: 3, [[PrimitiveValue]]: "abc"}
     0: "a"
     1: "b"
     2: "c"
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/agents-disabled-check-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/agents-disabled-check-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/agents-disabled-check-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/agents-disabled-check-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/agents-disabled-check.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/agents-disabled-check.html
similarity index 93%
rename from third_party/WebKit/LayoutTests/inspector/profiler/agents-disabled-check.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/agents-disabled-check.html
index f572a67..662ab57 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/agents-disabled-check.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/agents-disabled-check.html
@@ -1,6 +1,6 @@
 <html>
 <head>
-  <script src="../../http/tests/inspector/inspector-test.js"></script>
+  <script src="../../inspector/inspector-test.js"></script>
 <script>
 
 async function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-agent-crash-on-start-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-agent-crash-on-start-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-agent-crash-on-start-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-agent-crash-on-start-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-agent-crash-on-start.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-agent-crash-on-start.html
similarity index 86%
rename from third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-agent-crash-on-start.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-agent-crash-on-start.html
index 8210cc1..a62834f 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-agent-crash-on-start.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-agent-crash-on-start.html
@@ -1,6 +1,6 @@
 <html>
 <head>
-  <script src="../../http/tests/inspector/inspector-test.js"></script>
+  <script src="../../inspector/inspector-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-bottom-up-large-tree-search-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-bottom-up-large-tree-search-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-bottom-up-large-tree-search-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-bottom-up-large-tree-search-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-bottom-up-large-tree-search.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-bottom-up-large-tree-search.html
similarity index 94%
rename from third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-bottom-up-large-tree-search.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-bottom-up-large-tree-search.html
index fc59ec93..693e8ad 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-bottom-up-large-tree-search.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-bottom-up-large-tree-search.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-  <script src="../../http/tests/inspector/inspector-test.js"></script>
-  <script src="profiler-test.js"></script>
+  <script src="../../inspector/inspector-test.js"></script>
+  <script src="../resources/profiler-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-bottom-up-times-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-bottom-up-times-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-bottom-up-times-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-bottom-up-times-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-bottom-up-times.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-bottom-up-times.html
similarity index 95%
rename from third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-bottom-up-times.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-bottom-up-times.html
index f7da38f..c84e4ae 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-bottom-up-times.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-bottom-up-times.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-  <script src="../../http/tests/inspector/inspector-test.js"></script>
-  <script src="profiler-test.js"></script>
+  <script src="../../inspector/inspector-test.js"></script>
+  <script src="../resources/profiler-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-calculate-time-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-calculate-time-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-calculate-time-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-calculate-time-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-calculate-time.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-calculate-time.html
similarity index 96%
rename from third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-calculate-time.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-calculate-time.html
index aed7ce9e..4e9c941d 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-calculate-time.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-calculate-time.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-  <script src="../../http/tests/inspector/inspector-test.js"></script>
-  <script src="profiler-test.js"></script>
+  <script src="../../inspector/inspector-test.js"></script>
+  <script src="../resources/profiler-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-flame-chart-overview-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-flame-chart-overview-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-flame-chart-overview-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-flame-chart-overview-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-flame-chart-overview.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-flame-chart-overview.html
similarity index 99%
rename from third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-flame-chart-overview.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-flame-chart-overview.html
index 6fcf29d..b80fb90f7a 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-flame-chart-overview.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-flame-chart-overview.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-  <script src="../../http/tests/inspector/inspector-test.js"></script>
-  <script src="profiler-test.js"></script>
+  <script src="../../inspector/inspector-test.js"></script>
+  <script src="../resources/profiler-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-native-nodes-filter-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-native-nodes-filter-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-native-nodes-filter-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-native-nodes-filter-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-native-nodes-filter.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-native-nodes-filter.html
similarity index 96%
rename from third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-native-nodes-filter.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-native-nodes-filter.html
index 38cb68b1..d04b948e 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-native-nodes-filter.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-native-nodes-filter.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-  <script src="../../http/tests/inspector/inspector-test.js"></script>
-  <script src="profiler-test.js"></script>
+  <script src="../../inspector/inspector-test.js"></script>
+  <script src="../resources/profiler-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-profile-removal-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-profile-removal-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-profile-removal-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-profile-removal-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-profile-removal.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-profile-removal.html
similarity index 91%
rename from third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-profile-removal.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-profile-removal.html
index 0629799..7936d62 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-profile-removal.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-profile-removal.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-  <script src="../../http/tests/inspector/inspector-test.js"></script>
-  <script src="profiler-test.js"></script>
+  <script src="../../inspector/inspector-test.js"></script>
+  <script src="../resources/profiler-test.js"></script>
 <script>
 
 function pageFunction() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-profiling-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-profiling-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-profiling-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-profiling-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-profiling.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-profiling.html
similarity index 92%
rename from third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-profiling.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-profiling.html
index ea1f02e8..db38c1b 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-profiling.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-profiling.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-  <script src="../../http/tests/inspector/inspector-test.js"></script>
-  <script src="profiler-test.js"></script>
+  <script src="../../inspector/inspector-test.js"></script>
+  <script src="../resources/profiler-test.js"></script>
 <script>
 
 function pageFunction() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-save-load-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-save-load-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-save-load-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-save-load-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-save-load.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-save-load.html
similarity index 96%
rename from third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-save-load.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-save-load.html
index 21247e2..5f48ca5 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-save-load.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-save-load.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-  <script src="../../http/tests/inspector/inspector-test.js"></script>
-  <script src="profiler-test.js"></script>
+  <script src="../../inspector/inspector-test.js"></script>
+  <script src="../resources/profiler-test.js"></script>
 <script>
 
 function pageFunction() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-stopped-removed-race-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-stopped-removed-race-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-stopped-removed-race-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-stopped-removed-race-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-stopped-removed-race.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-stopped-removed-race.html
similarity index 92%
rename from third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-stopped-removed-race.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-stopped-removed-race.html
index 2b44012..ea6a443 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/cpu-profiler-stopped-removed-race.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/cpu-profiler-stopped-removed-race.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-  <script src="../../http/tests/inspector/inspector-test.js"></script>
-  <script src="profiler-test.js"></script>
+  <script src="../../inspector/inspector-test.js"></script>
+  <script src="../resources/profiler-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-profiler-profiling-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-profiler-profiling-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-profiler-profiling-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-profiler-profiling-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-profiler-profiling.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-profiler-profiling.html
similarity index 93%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-profiler-profiling.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-profiler-profiling.html
index 504fb7a..6f3e3ed 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/heap-profiler-profiling.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-profiler-profiling.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-  <script src="../../http/tests/inspector/inspector-test.js"></script>
-  <script src="profiler-test.js"></script>
+  <script src="../../inspector/inspector-test.js"></script>
+  <script src="../resources/profiler-test.js"></script>
 <script>
 
 function pageFunction() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-comparison-dom-groups-change-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-comparison-dom-groups-change-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-comparison-dom-groups-change-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-comparison-dom-groups-change-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-comparison-dom-groups-change.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-comparison-dom-groups-change.html
similarity index 96%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-comparison-dom-groups-change.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-comparison-dom-groups-change.html
index b6e0ad03..0e21b6e 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-comparison-dom-groups-change.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-comparison-dom-groups-change.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-  <script src="../../http/tests/inspector/inspector-test.js"></script>
-  <script src="heap-snapshot-test.js"></script>
+  <script src="../../inspector/inspector-test.js"></script>
+  <script src="../resources/heap-snapshot-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-comparison-expansion-preserved-when-sorting-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-comparison-expansion-preserved-when-sorting-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-comparison-expansion-preserved-when-sorting-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-comparison-expansion-preserved-when-sorting-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-comparison-expansion-preserved-when-sorting.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-comparison-expansion-preserved-when-sorting.html
similarity index 96%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-comparison-expansion-preserved-when-sorting.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-comparison-expansion-preserved-when-sorting.html
index 98427354..595bb3e9 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-comparison-expansion-preserved-when-sorting.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-comparison-expansion-preserved-when-sorting.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-  <script src="../../http/tests/inspector/inspector-test.js"></script>
-  <script src="heap-snapshot-test.js"></script>
+  <script src="../../inspector/inspector-test.js"></script>
+  <script src="../resources/heap-snapshot-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-comparison-show-all-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-comparison-show-all-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-comparison-show-all-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-comparison-show-all-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-comparison-show-all.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-comparison-show-all.html
similarity index 95%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-comparison-show-all.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-comparison-show-all.html
index bed2bfb..99180f25 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-comparison-show-all.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-comparison-show-all.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-  <script src="../../http/tests/inspector/inspector-test.js"></script>
-  <script src="heap-snapshot-test.js"></script>
+  <script src="../../inspector/inspector-test.js"></script>
+  <script src="../resources/heap-snapshot-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-comparison-show-next-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-comparison-show-next-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-comparison-show-next-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-comparison-show-next-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-comparison-show-next.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-comparison-show-next.html
similarity index 95%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-comparison-show-next.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-comparison-show-next.html
index 423be8d..e33fb2b 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-comparison-show-next.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-comparison-show-next.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-  <script src="../../http/tests/inspector/inspector-test.js"></script>
-  <script src="heap-snapshot-test.js"></script>
+  <script src="../../inspector/inspector-test.js"></script>
+  <script src="../resources/heap-snapshot-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-comparison-shown-node-count-preserved-when-sorting-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-comparison-shown-node-count-preserved-when-sorting-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-comparison-shown-node-count-preserved-when-sorting-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-comparison-shown-node-count-preserved-when-sorting-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-comparison-shown-node-count-preserved-when-sorting.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-comparison-shown-node-count-preserved-when-sorting.html
similarity index 95%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-comparison-shown-node-count-preserved-when-sorting.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-comparison-shown-node-count-preserved-when-sorting.html
index 103e3ac..36b4f65 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-comparison-shown-node-count-preserved-when-sorting.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-comparison-shown-node-count-preserved-when-sorting.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-  <script src="../../http/tests/inspector/inspector-test.js"></script>
-  <script src="heap-snapshot-test.js"></script>
+  <script src="../../inspector/inspector-test.js"></script>
+  <script src="../resources/heap-snapshot-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-comparison-sorting-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-comparison-sorting-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-comparison-sorting-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-comparison-sorting-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-comparison-sorting.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-comparison-sorting.html
similarity index 94%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-comparison-sorting.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-comparison-sorting.html
index 8db2023..bbcdcad 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-comparison-sorting.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-comparison-sorting.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-  <script src="../../http/tests/inspector/inspector-test.js"></script>
-  <script src="heap-snapshot-test.js"></script>
+  <script src="../../inspector/inspector-test.js"></script>
+  <script src="../resources/heap-snapshot-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-containment-expansion-preserved-when-sorting-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-containment-expansion-preserved-when-sorting-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-containment-expansion-preserved-when-sorting-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-containment-expansion-preserved-when-sorting-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-containment-expansion-preserved-when-sorting.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-containment-expansion-preserved-when-sorting.html
similarity index 94%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-containment-expansion-preserved-when-sorting.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-containment-expansion-preserved-when-sorting.html
index 0e5f2c8..4badfec5 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-containment-expansion-preserved-when-sorting.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-containment-expansion-preserved-when-sorting.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-  <script src="../../http/tests/inspector/inspector-test.js"></script>
-  <script src="heap-snapshot-test.js"></script>
+  <script src="../../inspector/inspector-test.js"></script>
+  <script src="../resources/heap-snapshot-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-containment-show-all-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-containment-show-all-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-containment-show-all-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-containment-show-all-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-containment-show-all.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-containment-show-all.html
similarity index 97%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-containment-show-all.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-containment-show-all.html
index 7b75127..a819350 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-containment-show-all.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-containment-show-all.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-  <script src="../../http/tests/inspector/inspector-test.js"></script>
-  <script src="heap-snapshot-test.js"></script>
+  <script src="../../inspector/inspector-test.js"></script>
+  <script src="../resources/heap-snapshot-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-containment-show-next-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-containment-show-next-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-containment-show-next-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-containment-show-next-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-containment-show-next.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-containment-show-next.html
similarity index 92%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-containment-show-next.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-containment-show-next.html
index e270c3b..2b903b03 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-containment-show-next.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-containment-show-next.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-  <script src="../../http/tests/inspector/inspector-test.js"></script>
-  <script src="heap-snapshot-test.js"></script>
+  <script src="../../inspector/inspector-test.js"></script>
+  <script src="../resources/heap-snapshot-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-containment-shown-node-count-preserved-when-sorting-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-containment-shown-node-count-preserved-when-sorting-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-containment-shown-node-count-preserved-when-sorting-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-containment-shown-node-count-preserved-when-sorting-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-containment-shown-node-count-preserved-when-sorting.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-containment-shown-node-count-preserved-when-sorting.html
similarity index 93%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-containment-shown-node-count-preserved-when-sorting.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-containment-shown-node-count-preserved-when-sorting.html
index 3aced4dd..330d804 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-containment-shown-node-count-preserved-when-sorting.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-containment-shown-node-count-preserved-when-sorting.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-  <script src="../../http/tests/inspector/inspector-test.js"></script>
-  <script src="heap-snapshot-test.js"></script>
+  <script src="../../inspector/inspector-test.js"></script>
+  <script src="../resources/heap-snapshot-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-containment-sorting-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-containment-sorting-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-containment-sorting-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-containment-sorting-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-containment-sorting.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-containment-sorting.html
similarity index 93%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-containment-sorting.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-containment-sorting.html
index 0ef91f2..33166764 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-containment-sorting.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-containment-sorting.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-  <script src="../../http/tests/inspector/inspector-test.js"></script>
-  <script src="heap-snapshot-test.js"></script>
+  <script src="../../inspector/inspector-test.js"></script>
+  <script src="../resources/heap-snapshot-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-inspect-dom-wrapper-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-inspect-dom-wrapper-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-inspect-dom-wrapper-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-inspect-dom-wrapper-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-inspect-dom-wrapper.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-inspect-dom-wrapper.html
similarity index 95%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-inspect-dom-wrapper.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-inspect-dom-wrapper.html
index 6bf1a7b0..251effa 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-inspect-dom-wrapper.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-inspect-dom-wrapper.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../http/tests/inspector/inspector-test.js"></script>
-<script src="heap-snapshot-test.js"></script>
+<script src="../../inspector/inspector-test.js"></script>
+<script src="../resources/heap-snapshot-test.js"></script>
 <script>
 
 function handleLoad()
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-loader-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-loader-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-loader-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-loader-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-loader.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-loader.html
similarity index 96%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-loader.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-loader.html
index 6550acf..997d053 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-loader.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-loader.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../http/tests/inspector/inspector-test.js"></script>
-<script src="heap-snapshot-test.js"></script>
+<script src="../../inspector/inspector-test.js"></script>
+<script src="../resources/heap-snapshot-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-orphan-nodes-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-orphan-nodes-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-orphan-nodes-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-orphan-nodes-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-orphan-nodes.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-orphan-nodes.html
similarity index 96%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-orphan-nodes.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-orphan-nodes.html
index 9409794..61c0c16 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-orphan-nodes.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-orphan-nodes.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-  <script src="../../http/tests/inspector/inspector-test.js"></script>
-  <script src="heap-snapshot-test.js"></script>
+  <script src="../../inspector/inspector-test.js"></script>
+  <script src="../resources/heap-snapshot-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-statistics-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-statistics-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-statistics-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-statistics-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-statistics.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-statistics.html
similarity index 94%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-statistics.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-statistics.html
index 99afbb8..957bb5dd 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-statistics.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-statistics.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-  <script src="../../http/tests/inspector/inspector-test.js"></script>
-  <script src="heap-snapshot-test.js"></script>
+  <script src="../../inspector/inspector-test.js"></script>
+  <script src="../resources/heap-snapshot-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-expand-collapse-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-expand-collapse-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-expand-collapse-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-expand-collapse-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-expand-collapse.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-expand-collapse.html
similarity index 88%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-expand-collapse.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-expand-collapse.html
index 19e88b6..b21fbf0 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-expand-collapse.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-expand-collapse.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-  <script src="../../http/tests/inspector/inspector-test.js"></script>
-  <script src="heap-snapshot-test.js"></script>
+  <script src="../../inspector/inspector-test.js"></script>
+  <script src="../resources/heap-snapshot-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-expansion-preserved-when-sorting-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-expansion-preserved-when-sorting-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-expansion-preserved-when-sorting-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-expansion-preserved-when-sorting-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-expansion-preserved-when-sorting.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-expansion-preserved-when-sorting.html
similarity index 94%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-expansion-preserved-when-sorting.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-expansion-preserved-when-sorting.html
index 7774536..33f10c3 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-expansion-preserved-when-sorting.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-expansion-preserved-when-sorting.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-  <script src="../../http/tests/inspector/inspector-test.js"></script>
-  <script src="heap-snapshot-test.js"></script>
+  <script src="../../inspector/inspector-test.js"></script>
+  <script src="../resources/heap-snapshot-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-retainers-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-retainers-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-retainers-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-retainers-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-retainers.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-retainers.html
similarity index 97%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-retainers.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-retainers.html
index 111df66..a51867a7 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-retainers.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-retainers.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-  <script src="../../http/tests/inspector/inspector-test.js"></script>
-  <script src="heap-snapshot-test.js"></script>
+  <script src="../../inspector/inspector-test.js"></script>
+  <script src="../resources/heap-snapshot-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-search-by-id-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-search-by-id-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-search-by-id-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-search-by-id-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-search-by-id.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-search-by-id.html
similarity index 95%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-search-by-id.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-search-by-id.html
index 5505db8..21abd09 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-search-by-id.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-search-by-id.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-  <script src="../../http/tests/inspector/inspector-test.js"></script>
-  <script src="heap-snapshot-test.js"></script>
+  <script src="../../inspector/inspector-test.js"></script>
+  <script src="../resources/heap-snapshot-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-search-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-search-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-search-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-search-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-search.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-search.html
similarity index 95%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-search.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-search.html
index 8393984..358fa18 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-search.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-search.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-  <script src="../../http/tests/inspector/inspector-test.js"></script>
-  <script src="heap-snapshot-test.js"></script>
+  <script src="../../inspector/inspector-test.js"></script>
+  <script src="../resources/heap-snapshot-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-show-all-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-show-all-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-show-all-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-show-all-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-show-all.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-show-all.html
similarity index 93%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-show-all.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-show-all.html
index 9f5ecf0f..b42f0f2 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-show-all.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-show-all.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-  <script src="../../http/tests/inspector/inspector-test.js"></script>
-  <script src="heap-snapshot-test.js"></script>
+  <script src="../../inspector/inspector-test.js"></script>
+  <script src="../resources/heap-snapshot-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-show-next-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-show-next-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-show-next-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-show-next-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-show-next.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-show-next.html
similarity index 92%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-show-next.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-show-next.html
index 92cd2ad..e523cd2 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-show-next.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-show-next.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-  <script src="../../http/tests/inspector/inspector-test.js"></script>
-  <script src="heap-snapshot-test.js"></script>
+  <script src="../../inspector/inspector-test.js"></script>
+  <script src="../resources/heap-snapshot-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-show-ranges-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-show-ranges-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-show-ranges-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-show-ranges-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-show-ranges.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-show-ranges.html
similarity index 92%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-show-ranges.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-show-ranges.html
index 080fb9d11..63d4448 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-show-ranges.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-show-ranges.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-    <script src="../../http/tests/inspector/inspector-test.js"></script>
-    <script src="heap-snapshot-test.js"></script>
+    <script src="../../inspector/inspector-test.js"></script>
+    <script src="../resources/heap-snapshot-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-shown-node-count-preserved-when-sorting-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-shown-node-count-preserved-when-sorting-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-shown-node-count-preserved-when-sorting-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-shown-node-count-preserved-when-sorting-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-shown-node-count-preserved-when-sorting.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-shown-node-count-preserved-when-sorting.html
similarity index 93%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-shown-node-count-preserved-when-sorting.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-shown-node-count-preserved-when-sorting.html
index 0688f00..cfe5621 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-shown-node-count-preserved-when-sorting.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-shown-node-count-preserved-when-sorting.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-  <script src="../../http/tests/inspector/inspector-test.js"></script>
-  <script src="heap-snapshot-test.js"></script>
+  <script src="../../inspector/inspector-test.js"></script>
+  <script src="../resources/heap-snapshot-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-sorting-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-sorting-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-sorting-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-sorting-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-sorting-fields-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-sorting-fields-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-sorting-fields-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-sorting-fields-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-sorting-fields.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-sorting-fields.html
similarity index 94%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-sorting-fields.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-sorting-fields.html
index 7b07053..7877a99b 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-sorting-fields.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-sorting-fields.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-  <script src="../../http/tests/inspector/inspector-test.js"></script>
-  <script src="heap-snapshot-test.js"></script>
+  <script src="../../inspector/inspector-test.js"></script>
+  <script src="../resources/heap-snapshot-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-sorting-instances-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-sorting-instances-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-sorting-instances-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-sorting-instances-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-sorting-instances.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-sorting-instances.html
similarity index 94%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-sorting-instances.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-sorting-instances.html
index 5c87376..1725db7 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-sorting-instances.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-sorting-instances.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-  <script src="../../http/tests/inspector/inspector-test.js"></script>
-  <script src="heap-snapshot-test.js"></script>
+  <script src="../../inspector/inspector-test.js"></script>
+  <script src="../resources/heap-snapshot-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-sorting.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-sorting.html
similarity index 93%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-sorting.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-sorting.html
index 34bc3c9..7edc506b 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-summary-sorting.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-summary-sorting.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-  <script src="../../http/tests/inspector/inspector-test.js"></script>
-  <script src="heap-snapshot-test.js"></script>
+  <script src="../../inspector/inspector-test.js"></script>
+  <script src="../resources/heap-snapshot-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-weak-dominator-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-weak-dominator-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-weak-dominator-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-weak-dominator-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-weak-dominator.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-weak-dominator.html
similarity index 95%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-weak-dominator.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-weak-dominator.html
index b1bbfa8..b5450dd 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-weak-dominator.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot-weak-dominator.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-  <script src="../../http/tests/inspector/inspector-test.js"></script>
-  <script src="heap-snapshot-test.js"></script>
+  <script src="../../inspector/inspector-test.js"></script>
+  <script src="../resources/heap-snapshot-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot.html b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot.html
similarity index 99%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot.html
index cbc57893..cd661ea 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/heap-snapshot.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../http/tests/inspector/inspector-test.js"></script>
-<script src="heap-snapshot-test.js"></script>
+<script src="../../inspector/inspector-test.js"></script>
+<script src="../resources/heap-snapshot-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/resources/image.jpeg b/third_party/WebKit/LayoutTests/http/tests/devtools/profiler/resources/image.jpeg
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/resources/image.jpeg
rename to third_party/WebKit/LayoutTests/http/tests/devtools/profiler/resources/image.jpeg
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-test.js b/third_party/WebKit/LayoutTests/http/tests/devtools/resources/heap-snapshot-test.js
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/heap-snapshot-test.js
rename to third_party/WebKit/LayoutTests/http/tests/devtools/resources/heap-snapshot-test.js
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/profiler-test.js b/third_party/WebKit/LayoutTests/http/tests/devtools/resources/profiler-test.js
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/profiler/profiler-test.js
rename to third_party/WebKit/LayoutTests/http/tests/devtools/resources/profiler-test.js
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/anonymous-image-object-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/anonymous-image-object-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/anonymous-image-object-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/anonymous-image-object-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/anonymous-image-object.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/anonymous-image-object.html
similarity index 86%
rename from third_party/WebKit/LayoutTests/inspector/tracing/anonymous-image-object.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/anonymous-image-object.html
index ac07550d0..df41c48b 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/anonymous-image-object.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/anonymous-image-object.html
@@ -5,8 +5,8 @@
     content: url(resources/test.bmp);
 }
 </style>
-<script src="../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../inspector/inspector-test.js"></script>
+<script src="../../inspector/timeline-test.js"></script>
 <script>
 
 function doActions()
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/buffer-usage-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/buffer-usage-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/buffer-usage-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/buffer-usage-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/buffer-usage.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/buffer-usage.html
similarity index 91%
rename from third_party/WebKit/LayoutTests/inspector/tracing/buffer-usage.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/buffer-usage.html
index 210b979..60d263a 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/buffer-usage.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/buffer-usage.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../inspector/inspector-test.js"></script>
+<script src="../../inspector/timeline-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/category-filter-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/category-filter-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/category-filter-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/category-filter-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/category-filter.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/category-filter.html
similarity index 96%
rename from third_party/WebKit/LayoutTests/inspector/tracing/category-filter.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/category-filter.html
index 30c92f58..d03f25e7 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/category-filter.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/category-filter.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../inspector/inspector-test.js"></script>
+<script src="../../inspector/timeline-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/console-timeline-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/console-timeline-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/console-timeline-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/console-timeline-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/console-timeline.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/console-timeline.html
similarity index 95%
rename from third_party/WebKit/LayoutTests/inspector/tracing/console-timeline.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/console-timeline.html
index 087f668..aa95b133 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/console-timeline.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/console-timeline.html
@@ -1,8 +1,8 @@
 <html>
 <head>
-<script src="../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../http/tests/inspector/console-test.js"></script>
-<script src="../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../inspector/inspector-test.js"></script>
+<script src="../../inspector/console-test.js"></script>
+<script src="../../inspector/timeline-test.js"></script>
 <script>
 
 testRunner.setDumpConsoleMessages(false);
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/decode-resize-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/decode-resize-expected.txt
new file mode 100644
index 0000000..cb1dec9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/decode-resize-expected.txt
@@ -0,0 +1,66 @@
+Tests the instrumentation of a DecodeImage and ResizeImage events
+
+event: Decode Image
+imageURL: http://127.0.0.1:8000/devtools/tracing/resources/big.png
+backendNodeId: present
+event: Decode Image
+imageURL: http://127.0.0.1:8000/devtools/tracing/resources/big.png?background
+backendNodeId: present
+event: Decode Image
+imageURL: http://127.0.0.1:8000/devtools/tracing/resources/big.png?border
+backendNodeId: present
+event: Decode Image
+imageURL: http://127.0.0.1:8000/devtools/tracing/resources/test.bmp
+backendNodeId: present
+event: Decode Image
+imageURL: http://127.0.0.1:8000/devtools/tracing/resources/test.bmp?background
+backendNodeId: present
+event: Decode Image
+imageURL: http://127.0.0.1:8000/devtools/tracing/resources/test.bmp?border
+backendNodeId: present
+event: Decode Image
+imageURL: http://127.0.0.1:8000/devtools/tracing/resources/test.gif
+backendNodeId: present
+event: Decode Image
+imageURL: http://127.0.0.1:8000/devtools/tracing/resources/test.gif?background
+backendNodeId: present
+event: Decode Image
+imageURL: http://127.0.0.1:8000/devtools/tracing/resources/test.gif?border
+backendNodeId: present
+event: Decode Image
+imageURL: http://127.0.0.1:8000/devtools/tracing/resources/test.ico
+backendNodeId: present
+event: Decode Image
+imageURL: http://127.0.0.1:8000/devtools/tracing/resources/test.ico?background
+backendNodeId: present
+event: Decode Image
+imageURL: http://127.0.0.1:8000/devtools/tracing/resources/test.ico?border
+backendNodeId: present
+event: Decode Image
+imageURL: http://127.0.0.1:8000/devtools/tracing/resources/test.jpg
+backendNodeId: present
+event: Decode Image
+imageURL: http://127.0.0.1:8000/devtools/tracing/resources/test.jpg?background
+backendNodeId: present
+event: Decode Image
+imageURL: http://127.0.0.1:8000/devtools/tracing/resources/test.jpg?border
+backendNodeId: present
+event: Decode Image
+imageURL: http://127.0.0.1:8000/devtools/tracing/resources/test.png
+backendNodeId: present
+event: Decode Image
+imageURL: http://127.0.0.1:8000/devtools/tracing/resources/test.png?background
+backendNodeId: present
+event: Decode Image
+imageURL: http://127.0.0.1:8000/devtools/tracing/resources/test.png?border
+backendNodeId: present
+event: Decode Image
+imageURL: http://127.0.0.1:8000/devtools/tracing/resources/test.webp
+backendNodeId: present
+event: Decode Image
+imageURL: http://127.0.0.1:8000/devtools/tracing/resources/test.webp?background
+backendNodeId: present
+event: Decode Image
+imageURL: http://127.0.0.1:8000/devtools/tracing/resources/test.webp?border
+backendNodeId: present
+
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/decode-resize.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/decode-resize.html
similarity index 95%
rename from third_party/WebKit/LayoutTests/inspector/tracing/decode-resize.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/decode-resize.html
index 6f6cda9..0d34b386 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/decode-resize.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/decode-resize.html
@@ -23,8 +23,8 @@
 }
 
 </style>
-<script src="../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../inspector/inspector-test.js"></script>
+<script src="../../inspector/timeline-test.js"></script>
 <script>
 
 var images = [
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/frame-model-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/frame-model-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/frame-model-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/frame-model-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/frame-model-instrumentation-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/frame-model-instrumentation-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/frame-model-instrumentation-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/frame-model-instrumentation-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/frame-model-instrumentation.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/frame-model-instrumentation.html
similarity index 87%
rename from third_party/WebKit/LayoutTests/inspector/tracing/frame-model-instrumentation.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/frame-model-instrumentation.html
index 4a448fe..24e50880 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/frame-model-instrumentation.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/frame-model-instrumentation.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../inspector/inspector-test.js"></script>
+<script src="../../inspector/timeline-test.js"></script>
 <script src="../tracing-test.js"></script>
 
 <script>
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/frame-model.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/frame-model.html
similarity index 99%
rename from third_party/WebKit/LayoutTests/inspector/tracing/frame-model.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/frame-model.html
index 6f34b2b..bda3a4b 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/frame-model.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/frame-model.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../inspector/inspector-test.js"></script>
+<script src="../../inspector/timeline-test.js"></script>
 <script src="../tracing-test.js"></script>
 <script>
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/hit-test-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/hit-test-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/hit-test-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/hit-test-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/hit-test.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/hit-test.html
similarity index 70%
rename from third_party/WebKit/LayoutTests/inspector/tracing/hit-test.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/hit-test.html
index 79dca42f..06708e9 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/hit-test.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/hit-test.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../inspector/inspector-test.js"></script>
+<script src="../../inspector/timeline-test.js"></script>
 <script>
 
 function performActions()
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/resources/anImage.png b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/resources/anImage.png
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/resources/anImage.png
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/resources/anImage.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/resources/anotherImage.png b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/resources/anotherImage.png
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/resources/anotherImage.png
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/resources/anotherImage.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/resources/big.png b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/resources/big.png
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/resources/big.png
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/resources/big.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/resources/hello.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/resources/hello.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/resources/hello.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/resources/hello.html
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/resources/style.css b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/resources/style.css
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/resources/style.css
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/resources/style.css
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/resources/test.bmp b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/resources/test.bmp
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/resources/test.bmp
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/resources/test.bmp
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/resources/test.gif b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/resources/test.gif
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/resources/test.gif
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/resources/test.gif
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/resources/test.ico b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/resources/test.ico
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/resources/test.ico
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/resources/test.ico
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/resources/test.jpg b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/resources/test.jpg
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/resources/test.jpg
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/resources/test.jpg
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/resources/test.png b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/resources/test.png
similarity index 100%
copy from third_party/WebKit/LayoutTests/inspector/tracing/resources/test.png
copy to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/resources/test.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/resources/test.webp b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/resources/test.webp
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/resources/test.webp
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/resources/test.webp
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/resources/timeline-data.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/resources/timeline-data.js
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/resources/timeline-data.js
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/resources/timeline-data.js
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/resources/timeline-iframe-data.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/resources/timeline-iframe-data.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/resources/timeline-iframe-data.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/resources/timeline-iframe-data.html
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/resources/timeline-iframe-paint.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/resources/timeline-iframe-paint.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/resources/timeline-iframe-paint.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/resources/timeline-iframe-paint.html
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/resources/timeline-iframe-with-style.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/resources/timeline-iframe-with-style.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/resources/timeline-iframe-with-style.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/resources/timeline-iframe-with-style.html
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/resources/timeline-network-resource.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/resources/timeline-network-resource.js
new file mode 100644
index 0000000..916a330
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/resources/timeline-network-resource.js
@@ -0,0 +1,7 @@
+// Sample script resource to find in timeline data
+
+var element = document.createElement("div");
+element.innerHTML = "Script resource loaded";
+document.body.appendChild(element);
+
+window.timelineNetworkResourceEvaluated();
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/resources/worker.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/resources/worker.js
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/resources/worker.js
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/resources/worker.js
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/scroll-invalidations-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/scroll-invalidations-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/scroll-invalidations-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/scroll-invalidations-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/scroll-invalidations.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/scroll-invalidations.html
similarity index 88%
rename from third_party/WebKit/LayoutTests/inspector/tracing/scroll-invalidations.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/scroll-invalidations.html
index 8f6ea67..f4d50e0 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/scroll-invalidations.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/scroll-invalidations.html
@@ -1,8 +1,8 @@
 <!DOCTYPE HTML>
 <html>
 <head>
-<script src="../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../inspector/inspector-test.js"></script>
+<script src="../../inspector/timeline-test.js"></script>
 <script>
 function scrollAndDisplay()
 {
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/compile-script-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/compile-script-expected.txt
similarity index 84%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/compile-script-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/compile-script-expected.txt
index 1ed50256..423e928 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/compile-script-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/compile-script-expected.txt
@@ -18,7 +18,7 @@
     data : {
         columnNumber : <number>
         lineNumber : <number>
-        url : .../inspector/tracing/timeline-js/timeline-script-tag-2.js
+        url : http://127.0.0.1:8000/devtools/tracing/timeline-js/resources/timeline-script-tag-2.js
     }
     endTime : <number>
     startTime : <number>
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/compile-script.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/compile-script.html
similarity index 77%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/compile-script.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/compile-script.html
index fd562aa7..b9e3291 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/compile-script.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/compile-script.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 
 function performActions()
@@ -12,7 +12,7 @@
     eval("function noop2() {} \n//# sourceURL=script-content.js");
 
     script = document.createElement("script");
-    script.src = "timeline-script-tag-2.js";
+    script.src = "resources/timeline-script-tag-2.js";
     document.body.appendChild(script);
 }
 
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-script-tag-2.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/resources/timeline-script-tag-2.js
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-script-tag-2.js
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/resources/timeline-script-tag-2.js
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-gc-event-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-gc-event-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-gc-event-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-gc-event-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-gc-event.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-gc-event.html
similarity index 86%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-gc-event.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-gc-event.html
index f0eee32..cdafa0af 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-gc-event.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-gc-event.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 
 function produceGarbageForGCEvents()
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-injected-script-eval-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-injected-script-eval-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-injected-script-eval-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-injected-script-eval-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-injected-script-eval.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-injected-script-eval.html
similarity index 72%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-injected-script-eval.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-injected-script-eval.html
index 358fc9fc..8eb9bd4 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-injected-script-eval.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-injected-script-eval.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 
 function performActions()
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-js-blackboxing-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-js-blackboxing-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-js-blackboxing-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-js-blackboxing-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-js-blackboxing.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-js-blackboxing.html
similarity index 97%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-js-blackboxing.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-js-blackboxing.html
index 0ad1f43..7d9201c7a 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-js-blackboxing.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-js-blackboxing.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 function test() {
   var sessionId = '6.23';
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-js-callstacks-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-js-callstacks-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-js-callstacks-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-js-callstacks-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-js-callstacks.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-js-callstacks.html
similarity index 98%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-js-callstacks.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-js-callstacks.html
index 1721adc..08ed458 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-js-callstacks.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-js-callstacks.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 function test() {
   var sessionId = '6.23';
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-js-line-level-profile-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-js-line-level-profile-expected.txt
similarity index 88%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-js-line-level-profile-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-js-line-level-profile-expected.txt
index b35172c..07369a5 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-js-line-level-profile-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-js-line-level-profile-expected.txt
@@ -1,5 +1,5 @@
 Tests that a line-level CPU profile is shown in the text editor.
-.../inspector/tracing/resources/timeline-data.js
+http://127.0.0.1:8000/devtools/tracing/resources/timeline-data.js
 99 CodeMirror-gutter-performance 10.0 ms rgba(255, 187, 0, 0.263)
 101 CodeMirror-gutter-performance 1900.0 ms rgba(255, 187, 0, 0.718)
 0 CodeMirror-gutter-performance 100.0 ms rgba(255, 187, 0, 0.463)
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-js-line-level-profile.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-js-line-level-profile.html
similarity index 92%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-js-line-level-profile.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-js-line-level-profile.html
index 0747996..498969d 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-js-line-level-profile.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-js-line-level-profile.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/debugger-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/debugger-test.js"></script>
 <script src="../resources/timeline-data.js"></script>
 <script>
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-js-streamed-cpu-profile-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-js-streamed-cpu-profile-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-js-streamed-cpu-profile-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-js-streamed-cpu-profile-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-js-streamed-cpu-profile.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-js-streamed-cpu-profile.html
similarity index 95%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-js-streamed-cpu-profile.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-js-streamed-cpu-profile.html
index b6cb4b9..d160145 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-js-streamed-cpu-profile.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-js-streamed-cpu-profile.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 function test() {
   var sessionId = '6.23';
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-microtasks-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-microtasks-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-microtasks-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-microtasks-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-microtasks.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-microtasks.html
similarity index 86%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-microtasks.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-microtasks.html
index dc70813..ff8330f5 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-microtasks.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-microtasks.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 
 var scriptUrl = "timeline-network-resource.js";
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-open-function-call-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-open-function-call-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-open-function-call-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-open-function-call-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-open-function-call.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-open-function-call.html
similarity index 91%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-open-function-call.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-open-function-call.html
index d362807..b1273cb 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-open-function-call.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-open-function-call.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-runtime-stats-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-runtime-stats-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-runtime-stats-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-runtime-stats-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-runtime-stats.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-runtime-stats.html
similarity index 87%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-runtime-stats.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-runtime-stats.html
index 25105fb09..f048aa1 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-runtime-stats.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-runtime-stats.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 
 function performActions()
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-script-id-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-script-id-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-script-id-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-script-id-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-script-id.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-script-id.html
similarity index 93%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-script-id.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-script-id.html
index dca2ea65..4758b1f7 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-script-id.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-script-id.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-script-tag-1-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-script-tag-1-expected.txt
similarity index 84%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-script-tag-1-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-script-tag-1-expected.txt
index 75665e6..fea63bc 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-script-tag-1-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-script-tag-1-expected.txt
@@ -16,7 +16,7 @@
         columnNumber : <number>
         frame : <string>
         lineNumber : <number>
-        url : .../inspector/tracing/resources/timeline-iframe-data.html
+        url : http://127.0.0.1:8000/devtools/tracing/resources/timeline-iframe-data.html
     }
     endTime : <number>
     frameId : <string>
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-script-tag-1.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-script-tag-1.html
similarity index 88%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-script-tag-1.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-script-tag-1.html
index a7c81aa..ca09f96 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-script-tag-1.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-script-tag-1.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 
 function performActions()
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-script-tag-2-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-script-tag-2-expected.txt
similarity index 82%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-script-tag-2-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-script-tag-2-expected.txt
index 53ba8939..1dab127 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-script-tag-2-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-script-tag-2-expected.txt
@@ -15,7 +15,7 @@
         columnNumber : <number>
         frame : <string>
         lineNumber : <number>
-        url : .../inspector/tracing/timeline-js/timeline-script-tag-2.js
+        url : http://127.0.0.1:8000/devtools/tracing/timeline-js/resources/timeline-script-tag-2.js
     }
     endTime : <number>
     frameId : <string>
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-script-tag-2.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-script-tag-2.html
similarity index 78%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-script-tag-2.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-script-tag-2.html
index 4138eadf..84eef1e3 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-js/timeline-script-tag-2.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-script-tag-2.html
@@ -1,13 +1,13 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 
 function performActions()
 {
     var script = document.createElement("script");
-    script.src = "timeline-script-tag-2.js";
+    script.src = "resources/timeline-script-tag-2.js";
     document.body.appendChild(script);
 }
 
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-layout/timeline-layout-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-layout/timeline-layout-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-layout/timeline-layout-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-layout/timeline-layout-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-layout/timeline-layout-reason-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-layout/timeline-layout-reason-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-layout/timeline-layout-reason-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-layout/timeline-layout-reason-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-layout/timeline-layout-reason.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-layout/timeline-layout-reason.html
similarity index 88%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-layout/timeline-layout-reason.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-layout/timeline-layout-reason.html
index bbff226c..ef5da0f 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-layout/timeline-layout-reason.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-layout/timeline-layout-reason.html
@@ -3,8 +3,8 @@
 .test { height: 20px; }
 </style>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 
 function invalidateStyle()
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-layout/timeline-layout-with-invalidations-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-layout/timeline-layout-with-invalidations-expected.txt
similarity index 69%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-layout/timeline-layout-with-invalidations-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-layout/timeline-layout-with-invalidations-expected.txt
index 973d3fad..70a34ef 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-layout/timeline-layout-with-invalidations-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-layout/timeline-layout-with-invalidations-expected.txt
@@ -6,7 +6,7 @@
 Running: testLocalFrame
 first layout invalidations[
     {
-        cause : {reason: Style changed, stackTrace: .../inspector/tracing/timeline-layout/timeline-layout-with-invalidations.html:10}
+        cause : {reason: Style changed, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-layout/timeline-layout-with-invalidations.html:10}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
@@ -19,7 +19,7 @@
 ]
 second layout invalidations[
     {
-        cause : {reason: Style changed, stackTrace: .../inspector/tracing/timeline-layout/timeline-layout-with-invalidations.html:12}
+        cause : {reason: Style changed, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-layout/timeline-layout-with-invalidations.html:12}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
@@ -34,7 +34,7 @@
 Running: testSubframe
 first layout invalidations[
     {
-        cause : {reason: Style changed, stackTrace: .../inspector/tracing/timeline-layout/timeline-layout-with-invalidations.html:19}
+        cause : {reason: Style changed, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-layout/timeline-layout-with-invalidations.html:19}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
@@ -47,7 +47,7 @@
 ]
 second layout invalidations[
     {
-        cause : {reason: Style changed, stackTrace: .../inspector/tracing/timeline-layout/timeline-layout-with-invalidations.html:21}
+        cause : {reason: Style changed, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-layout/timeline-layout-with-invalidations.html:21}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-layout/timeline-layout-with-invalidations.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-layout/timeline-layout-with-invalidations.html
similarity index 93%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-layout/timeline-layout-with-invalidations.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-layout/timeline-layout-with-invalidations.html
index 48849ea0..74ecc01f 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-layout/timeline-layout-with-invalidations.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-layout/timeline-layout-with-invalidations.html
@@ -1,8 +1,8 @@
 <!DOCTYPE HTML>
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 function display()
 {
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-layout/timeline-layout.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-layout/timeline-layout.html
similarity index 87%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-layout/timeline-layout.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-layout/timeline-layout.html
index e11a3f95..a43d2089 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-layout/timeline-layout.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-layout/timeline-layout.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <style>
 .relayout-boundary {
     overflow: hidden;
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-aggregated-details-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-aggregated-details-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-aggregated-details-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-aggregated-details-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-aggregated-details.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-aggregated-details.html
similarity index 98%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-aggregated-details.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-aggregated-details.html
index d555e578..a43bf88c 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-aggregated-details.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-aggregated-details.html
@@ -1,8 +1,8 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
-<script src="../../../http/tests/inspector/product-registry-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
+<script src="../../../inspector/product-registry-test.js"></script>
 <script>
 
 function initialize_ProductsExperiment()
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-animation-frame-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-animation-frame-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-animation-frame-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-animation-frame-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-animation-frame.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-animation-frame.html
similarity index 86%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-animation-frame.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-animation-frame.html
index e7e8df31..5146c2a 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-animation-frame.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-animation-frame.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 function performActions()
 {
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-auto-zoom-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-auto-zoom-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-auto-zoom-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-auto-zoom-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-auto-zoom.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-auto-zoom.html
similarity index 95%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-auto-zoom.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-auto-zoom.html
index 2255538..1f26d49 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-auto-zoom.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-auto-zoom.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 function test() {
   var sessionId = '4.20';
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-bound-function-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-bound-function-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-bound-function-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-bound-function-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-bound-function.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-bound-function.html
similarity index 86%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-bound-function.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-bound-function.html
index 909cb0e..4c9cc2a 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-bound-function.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-bound-function.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 
 function original() { }
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-event-causes-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-event-causes-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-event-causes-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-event-causes-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-event-causes.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-event-causes.html
similarity index 97%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-event-causes.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-event-causes.html
index 5da57ba..aa70cba 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-event-causes.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-event-causes.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 function test() {
   function checkStringContains(string, contains) {
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-event-details-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-event-details-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-event-details-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-event-details-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-event-details.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-event-details.html
similarity index 90%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-event-details.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-event-details.html
index ea152e1..05b44c2e8 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-event-details.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-event-details.html
@@ -1,8 +1,8 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
-<script src="../../../http/tests/inspector/product-registry-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
+<script src="../../../inspector/product-registry-test.js"></script>
 <script>
 
 async function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-event-dispatch-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-event-dispatch-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-event-dispatch-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-event-dispatch-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-event-dispatch.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-event-dispatch.html
similarity index 85%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-event-dispatch.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-event-dispatch.html
index e8f07237..d73ac6b3 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-event-dispatch.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-event-dispatch.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 
 function handleMouseDown(event) 
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-filtering-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-filtering-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-filtering-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-filtering-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-filtering.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-filtering.html
similarity index 97%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-filtering.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-filtering.html
index 46a9845..e412c34 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-filtering.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-filtering.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-flame-chart-automatically-size-window-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-flame-chart-automatically-size-window-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-flame-chart-automatically-size-window-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-flame-chart-automatically-size-window-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-flame-chart-automatically-size-window.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-flame-chart-automatically-size-window.html
similarity index 75%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-flame-chart-automatically-size-window.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-flame-chart-automatically-size-window.html
index 8ccb0db..780c942 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-flame-chart-automatically-size-window.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-flame-chart-automatically-size-window.html
@@ -1,8 +1,8 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/console-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/console-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script src="../resources/timeline-data.js"></script>
 <script>
 
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-grouped-invalidations-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-grouped-invalidations-expected.txt
similarity index 79%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-grouped-invalidations-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-grouped-invalidations-expected.txt
index b170d98..2e8b5fd 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-grouped-invalidations-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-grouped-invalidations-expected.txt
@@ -6,7 +6,7 @@
 S
 paint invalidations[
     {
-        cause : {reason: Inline CSS style declaration was mutated, stackTrace: .../inspector/tracing/timeline-misc/timeline-grouped-invalidations.html:14}
+        cause : {reason: Inline CSS style declaration was mutated, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-misc/timeline-grouped-invalidations.html:14}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
@@ -17,7 +17,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Inline CSS style declaration was mutated, stackTrace: .../inspector/tracing/timeline-misc/timeline-grouped-invalidations.html:15}
+        cause : {reason: Inline CSS style declaration was mutated, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-misc/timeline-grouped-invalidations.html:15}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
@@ -28,7 +28,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Inline CSS style declaration was mutated, stackTrace: .../inspector/tracing/timeline-misc/timeline-grouped-invalidations.html:14}
+        cause : {reason: Inline CSS style declaration was mutated, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-misc/timeline-grouped-invalidations.html:14}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
@@ -39,7 +39,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Inline CSS style declaration was mutated, stackTrace: .../inspector/tracing/timeline-misc/timeline-grouped-invalidations.html:15}
+        cause : {reason: Inline CSS style declaration was mutated, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-misc/timeline-grouped-invalidations.html:15}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
@@ -50,7 +50,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Inline CSS style declaration was mutated, stackTrace: .../inspector/tracing/timeline-misc/timeline-grouped-invalidations.html:14}
+        cause : {reason: Inline CSS style declaration was mutated, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-misc/timeline-grouped-invalidations.html:14}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
@@ -61,7 +61,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Inline CSS style declaration was mutated, stackTrace: .../inspector/tracing/timeline-misc/timeline-grouped-invalidations.html:15}
+        cause : {reason: Inline CSS style declaration was mutated, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-misc/timeline-grouped-invalidations.html:15}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
@@ -72,7 +72,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Inline CSS style declaration was mutated, stackTrace: .../inspector/tracing/timeline-misc/timeline-grouped-invalidations.html:14}
+        cause : {reason: Inline CSS style declaration was mutated, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-misc/timeline-grouped-invalidations.html:14}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
@@ -83,7 +83,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Inline CSS style declaration was mutated, stackTrace: .../inspector/tracing/timeline-misc/timeline-grouped-invalidations.html:15}
+        cause : {reason: Inline CSS style declaration was mutated, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-misc/timeline-grouped-invalidations.html:15}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-grouped-invalidations.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-grouped-invalidations.html
similarity index 94%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-grouped-invalidations.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-grouped-invalidations.html
index b5df536d..5ca04ae 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-grouped-invalidations.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-grouped-invalidations.html
@@ -1,8 +1,8 @@
 <!DOCTYPE HTML>
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 function display()
 {
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-load-event-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-load-event-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-load-event-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-load-event-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-load-event.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-load-event.html
similarity index 91%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-load-event.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-load-event.html
index c35ab35..327999c 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-load-event.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-load-event.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 function display()
 {
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-mark-timeline-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-mark-timeline-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-mark-timeline-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-mark-timeline-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-mark-timeline.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-mark-timeline.html
similarity index 68%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-mark-timeline.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-mark-timeline.html
index 8b23aab8..2b06ad6 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-mark-timeline.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-mark-timeline.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 
 function performActions()
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-model-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-model-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-model-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-model-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-model.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-model.html
similarity index 96%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-model.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-model.html
index 18a4960..0cd62e1 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-model.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-model.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 function test() {
   var sessionId = '4.20';
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-node-reference-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-node-reference-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-node-reference-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-node-reference-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-node-reference.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-node-reference.html
similarity index 89%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-node-reference.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-node-reference.html
index 8d2a5f04..0544c6d 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-node-reference.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-node-reference.html
@@ -1,8 +1,8 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/elements-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/elements-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <style>
 .relayout-boundary {
     overflow: hidden;
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-parse-html-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-parse-html-expected.txt
similarity index 81%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-parse-html-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-parse-html-expected.txt
index 5270887..d1f1368 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-parse-html-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-parse-html-expected.txt
@@ -8,7 +8,7 @@
             frame : <string>
             stackTrace : <object>
             startLine : 0
-            url : .../inspector/tracing/timeline-misc/timeline-parse-html.html
+            url : http://127.0.0.1:8000/devtools/tracing/timeline-misc/timeline-parse-html.html
         }
         endData : {
             endLine : -1
@@ -28,7 +28,7 @@
             frame : <string>
             stackTrace : <object>
             startLine : 0
-            url : .../inspector/tracing/timeline-misc/timeline-parse-html.html
+            url : http://127.0.0.1:8000/devtools/tracing/timeline-misc/timeline-parse-html.html
         }
         endData : {
             endLine : -1
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-parse-html.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-parse-html.html
similarity index 76%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-parse-html.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-parse-html.html
index a3b8885d..2cdb812 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-parse-html.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-parse-html.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 
 function performActions()
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-range-stats-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-range-stats-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-range-stats-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-range-stats-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-range-stats.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-range-stats.html
similarity index 94%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-range-stats.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-range-stats.html
index 0fed7eec..38d6156 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-range-stats.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-range-stats.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 function test() {
   var mainThread = 1;
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-record-reload-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-record-reload-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-record-reload-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-record-reload-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-record-reload.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-record-reload.html
similarity index 67%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-record-reload.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-record-reload.html
index 586666f..f01b4a6 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-record-reload.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-record-reload.html
@@ -1,8 +1,8 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/console-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/console-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-search-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-search-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-search-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-search-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-search.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-search.html
similarity index 96%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-search.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-search.html
index c903826..54411fe 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-search.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-search.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-tree-search-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-tree-search-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-tree-search-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-tree-search-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-tree-search.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-tree-search.html
similarity index 97%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-tree-search.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-tree-search.html
index 8eca7212f..f4cc76d 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-tree-search.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-tree-search.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 
 async function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-trivial-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-trivial-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-trivial-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-trivial-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-trivial.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-trivial.html
similarity index 72%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-trivial.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-trivial.html
index dd6bb8f..6d40982 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-trivial.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-trivial.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-window-filter-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-window-filter-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-window-filter-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-window-filter-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-window-filter.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-window-filter.html
similarity index 93%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-window-filter.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-window-filter.html
index b02c6fc2..dde0c2a 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-window-filter.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-window-filter.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script src="../resources/timeline-data.js"></script>
 <script>
 
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-network/timeline-network-resource-details-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-network/timeline-network-resource-details-expected.txt
similarity index 89%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-network/timeline-network-resource-details-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-network/timeline-network-resource-details-expected.txt
index c6f094f..5625b28 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-network/timeline-network-resource-details-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-network/timeline-network-resource-details-expected.txt
@@ -6,7 +6,7 @@
 Request Method: GET
 Priority: Low
 Mime Type: string
-Encoded Data: 223 B
+Encoded Data: string
 Decoded Body: 223 B
 Initiator: timeline-network-resource-details.html:15
 URL: anImage.png
@@ -14,7 +14,7 @@
 Request Method: GET
 Priority: Low
 Mime Type: string
-Encoded Data: 12.9 KB
+Encoded Data: string
 Decoded Body: 12.9 KB
 Preview: 
 
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-network/timeline-network-resource-details.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-network/timeline-network-resource-details.html
similarity index 82%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-network/timeline-network-resource-details.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-network/timeline-network-resource-details.html
index 077e5c1..250db6c4 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-network/timeline-network-resource-details.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-network/timeline-network-resource-details.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 
 function performActions()
@@ -11,7 +11,7 @@
     image.src = "../resources/anImage.png";
 
     var script = document.createElement("script");
-    script.src = "../../../http/tests/inspector/tracing/resources/timeline-network-resource.js";
+    script.src = "../resources/timeline-network-resource.js";
     document.body.appendChild(script);
     var scriptPromise = new Promise((fulfill) => window.timelineNetworkResourceEvaluated = fulfill);
 
@@ -19,6 +19,7 @@
 }
 
 async function test() {
+  await TestRunner.NetworkAgent.setCacheDisabled(true);
   await new Promise(fulfill => PerformanceTestRunner.invokeAsyncWithTimeline('performActions', fulfill));
 
   var model = PerformanceTestRunner.timelineModel();
@@ -36,7 +37,7 @@
     for (var i = 0; i < rows.length; ++i) {
       var title = TestRunner.deepTextContent(rows[i].firstChild);
       var value = TestRunner.deepTextContent(rows[i].lastChild);
-      if (title === 'Duration' || title === 'Mime Type')
+      if (title === 'Duration' || title === 'Mime Type' || title === 'Encoded Data')
         value = typeof value;
       if (/^file:\/\//.test(value))
         value = /[^/]*$/.exec(value)[0];
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-network/timeline-network-resource-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-network/timeline-network-resource-expected.txt
similarity index 87%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-network/timeline-network-resource-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-network/timeline-network-resource-expected.txt
index 0f117dc..758277e6 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-network/timeline-network-resource-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-network/timeline-network-resource-expected.txt
@@ -10,7 +10,7 @@
         requestId : <string>
         requestMethod : "GET"
         stackTrace : <object>
-        url : .../inspector/tracing/resources/timeline-network-resource.js
+        url : http://127.0.0.1:8000/devtools/tracing/resources/timeline-network-resource.js
     }
     endTime : <number>
     frameId : <string>
@@ -29,7 +29,8 @@
         fromServiceWorker : false
         mimeType : <string>
         requestId : <string>
-        statusCode : 0
+        statusCode : 200
+        timing : <object>
     }
     endTime : <number>
     frameId : <string>
@@ -37,6 +38,7 @@
     type : "ResourceReceiveResponse"
 }
 Text details for ResourceReceiveResponse: timeline-network-resource.js
+Response received status: 200
 
 ResourceFinish Properties:
 {
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-network/timeline-network-resource.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-network/timeline-network-resource.html
similarity index 89%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-network/timeline-network-resource.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-network/timeline-network-resource.html
index 28c0d06..66e37cb1 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-network/timeline-network-resource.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-network/timeline-network-resource.html
@@ -1,10 +1,10 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 
-var scriptUrl = "../../../http/tests/inspector/tracing/resources/timeline-network-resource.js";
+var scriptUrl = "../resources/timeline-network-resource.js";
 
 function performActions()
 {
@@ -15,7 +15,8 @@
     return promise;
 }
 
-function test() {
+async function test() {
+  await TestRunner.NetworkAgent.setCacheDisabled(true);
   var requestId;
   var scriptUrl = 'timeline-network-resource.js';
 
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/layer-tree-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/layer-tree-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/layer-tree-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/layer-tree-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/layer-tree.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/layer-tree.html
similarity index 87%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/layer-tree.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/layer-tree.html
index ef9d5e0..abb335a 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/layer-tree.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/layer-tree.html
@@ -1,8 +1,8 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
-<script src="../../../http/tests/inspector/layers-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
+<script src="../../../inspector/layers-test.js"></script>
 <script src="../../tracing-test.js"></script>
 
 <script>
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/paint-profiler-update-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/paint-profiler-update-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/paint-profiler-update-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/paint-profiler-update-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/paint-profiler-update.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/paint-profiler-update.html
similarity index 94%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/paint-profiler-update.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/paint-profiler-update.html
index c751dbab..92a940d 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/paint-profiler-update.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/paint-profiler-update.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 function performActions()
 {
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations-expected.txt
similarity index 76%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations-expected.txt
index d3f1152..796c4ae3 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations-expected.txt
@@ -5,7 +5,7 @@
 PASS
 first style recalc[
     {
-        cause : {reason: Element has pending invalidation list, stackTrace: .../inspector/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations.html:9}
+        cause : {reason: Element has pending invalidation list, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations.html:9}
         changedAttribute : undefined
         changedClass : "red"
         changedId : undefined
@@ -18,7 +18,7 @@
 ]
 second style recalc[
     {
-        cause : {reason: Element has pending invalidation list, stackTrace: .../inspector/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations.html:11}
+        cause : {reason: Element has pending invalidation list, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations.html:11}
         changedAttribute : undefined
         changedClass : "snow"
         changedId : undefined
@@ -29,7 +29,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Element has pending invalidation list, stackTrace: .../inspector/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations.html:11}
+        cause : {reason: Element has pending invalidation list, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations.html:11}
         changedAttribute : undefined
         changedClass : "red"
         changedId : undefined
@@ -42,7 +42,7 @@
 ]
 first paint[
     {
-        cause : {reason: Element has pending invalidation list, stackTrace: .../inspector/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations.html:9}
+        cause : {reason: Element has pending invalidation list, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations.html:9}
         changedAttribute : undefined
         changedClass : "red"
         changedId : undefined
@@ -53,7 +53,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Element has pending invalidation list, stackTrace: .../inspector/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations.html:11}
+        cause : {reason: Element has pending invalidation list, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations.html:11}
         changedAttribute : undefined
         changedClass : "snow"
         changedId : undefined
@@ -64,7 +64,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Element has pending invalidation list, stackTrace: .../inspector/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations.html:11}
+        cause : {reason: Element has pending invalidation list, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations.html:11}
         changedAttribute : undefined
         changedClass : "red"
         changedId : undefined
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations.html
similarity index 93%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations.html
index 76312ba5..8464e7fa 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations.html
@@ -1,8 +1,8 @@
 <!DOCTYPE HTML>
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 function multipleStyleRecalcsAndDisplay()
 {
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/timeline-paint-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/timeline-paint-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/timeline-paint-image-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-image-expected.txt
similarity index 80%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/timeline-paint-image-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-image-expected.txt
index 0a5887b..fb0a68b 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/timeline-paint-image-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-image-expected.txt
@@ -8,7 +8,7 @@
         nodeId : <number>
         srcHeight : 21
         srcWidth : 19
-        url : .../inspector/tracing/resources/test.png
+        url : http://127.0.0.1:8000/devtools/tracing/resources/test.png
         width : 40
         x : 0
         y : 100
@@ -24,7 +24,7 @@
         nodeId : <number>
         srcHeight : 21
         srcWidth : 19
-        url : .../inspector/tracing/resources/test.png
+        url : http://127.0.0.1:8000/devtools/tracing/resources/test.png
         width : 30
         x : 100
         y : 100
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/timeline-paint-image.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-image.html
similarity index 90%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/timeline-paint-image.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-image.html
index deb09ff7..bfbcac4 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/timeline-paint-image.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-image.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 
 function addImage(url, width, height)
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/timeline-paint-with-layout-invalidations-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-expected.txt
similarity index 72%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/timeline-paint-with-layout-invalidations-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-expected.txt
index e275fbc..d6903a8 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/timeline-paint-with-layout-invalidations-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-expected.txt
@@ -6,7 +6,7 @@
 Running: testLocalFrame
 paint invalidations[
     {
-        cause : {reason: Inline CSS style declaration was mutated, stackTrace: .../inspector/tracing/timeline-paint/timeline-paint-with-layout-invalidations.html:9}
+        cause : {reason: Inline CSS style declaration was mutated, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations.html:9}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
@@ -21,7 +21,7 @@
 Running: testSubframe
 second paint invalidations[
     {
-        cause : {reason: Inline CSS style declaration was mutated, stackTrace: .../inspector/tracing/timeline-paint/timeline-paint-with-layout-invalidations.html:17}
+        cause : {reason: Inline CSS style declaration was mutated, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations.html:17}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
@@ -32,7 +32,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Style changed, stackTrace: .../inspector/tracing/timeline-paint/timeline-paint-with-layout-invalidations.html:18}
+        cause : {reason: Style changed, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations.html:18}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
@@ -43,7 +43,7 @@
         type : "LayoutInvalidationTracking"
     }
     {
-        cause : {reason: Unknown, stackTrace: .../inspector/tracing/timeline-paint/timeline-paint-with-layout-invalidations.html:18}
+        cause : {reason: Unknown, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations.html:18}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node-expected.txt
similarity index 67%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node-expected.txt
index f251fd46..55df4a6c 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node-expected.txt
@@ -5,7 +5,7 @@
 Running: testLocalFrame
 paint invalidations[
     {
-        cause : {reason: Inline CSS style declaration was mutated, stackTrace: .../inspector/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.html:9}
+        cause : {reason: Inline CSS style declaration was mutated, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.html:9}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
@@ -16,7 +16,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Inline CSS style declaration was mutated, stackTrace: .../inspector/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.html:11}
+        cause : {reason: Inline CSS style declaration was mutated, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.html:11}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
@@ -27,7 +27,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Style changed, stackTrace: .../inspector/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.html:12}
+        cause : {reason: Style changed, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.html:12}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
@@ -38,7 +38,7 @@
         type : "LayoutInvalidationTracking"
     }
     {
-        cause : {reason: Removed from layout, stackTrace: .../inspector/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.html:13}
+        cause : {reason: Removed from layout, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.html:13}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
@@ -49,7 +49,7 @@
         type : "LayoutInvalidationTracking"
     }
     {
-        cause : {reason: Removed from layout, stackTrace: .../inspector/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.html:13}
+        cause : {reason: Removed from layout, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.html:13}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
@@ -64,7 +64,7 @@
 Running: testSubframe
 second paint invalidations[
     {
-        cause : {reason: Inline CSS style declaration was mutated, stackTrace: .../inspector/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.html:20}
+        cause : {reason: Inline CSS style declaration was mutated, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.html:20}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
@@ -75,7 +75,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Style changed, stackTrace: .../inspector/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.html:21}
+        cause : {reason: Style changed, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.html:21}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
@@ -86,7 +86,7 @@
         type : "LayoutInvalidationTracking"
     }
     {
-        cause : {reason: Removed from layout, stackTrace: .../inspector/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.html:22}
+        cause : {reason: Removed from layout, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.html:22}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.html
similarity index 93%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.html
index 5db6d86..662eeb09 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.html
@@ -1,8 +1,8 @@
 <!DOCTYPE HTML>
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 function display()
 {
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/timeline-paint-with-layout-invalidations.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations.html
similarity index 92%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/timeline-paint-with-layout-invalidations.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations.html
index 72b7008..043255c 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/timeline-paint-with-layout-invalidations.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations.html
@@ -1,8 +1,8 @@
 <!DOCTYPE HTML>
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 function display()
 {
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations-expected.txt
similarity index 77%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations-expected.txt
index 849e84d..08d26e9 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations-expected.txt
@@ -6,7 +6,7 @@
 Running: testLocalFrame
 first paint invalidations[
     {
-        cause : {reason: Inline CSS style declaration was mutated, stackTrace: .../inspector/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations.html:9}
+        cause : {reason: Inline CSS style declaration was mutated, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations.html:9}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
@@ -21,7 +21,7 @@
 Running: testSubframe
 second paint invalidations[
     {
-        cause : {reason: Inline CSS style declaration was mutated, stackTrace: .../inspector/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations.html:16}
+        cause : {reason: Inline CSS style declaration was mutated, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations.html:16}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations.html
similarity index 92%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations.html
index d58559e..23c7c82 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations.html
@@ -1,8 +1,8 @@
 <!DOCTYPE HTML>
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 function display()
 {
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/timeline-paint.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint.html
similarity index 93%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/timeline-paint.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint.html
index ab16b84..56bda278 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/timeline-paint.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 
 function display()
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/update-layer-tree-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/update-layer-tree-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/update-layer-tree-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/update-layer-tree-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/update-layer-tree.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/update-layer-tree.html
similarity index 88%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/update-layer-tree.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/update-layer-tree.html
index 052ea50..53d3da7 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-paint/update-layer-tree.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/update-layer-tree.html
@@ -8,8 +8,8 @@
     transform: translateZ(10px);
 }
 </style>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 
 function doActions()
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-style/parse-author-style-sheet-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/parse-author-style-sheet-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-style/parse-author-style-sheet-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/parse-author-style-sheet-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-style/parse-author-style-sheet.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/parse-author-style-sheet.html
similarity index 86%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-style/parse-author-style-sheet.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/parse-author-style-sheet.html
index 8422ee96..3437786 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-style/parse-author-style-sheet.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/parse-author-style-sheet.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script src="../../tracing-test.js"></script>
 <script>
 
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-style/timeline-recalculate-styles-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/timeline-recalculate-styles-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-style/timeline-recalculate-styles-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/timeline-recalculate-styles-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-style/timeline-recalculate-styles.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/timeline-recalculate-styles.html
similarity index 82%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-style/timeline-recalculate-styles.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/timeline-recalculate-styles.html
index 30fc2fa..7659c483 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-style/timeline-recalculate-styles.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/timeline-recalculate-styles.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 
 <style>
 .test-style {
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-style/timeline-style-recalc-all-invalidator-types-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-all-invalidator-types-expected.txt
similarity index 73%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-style/timeline-style-recalc-all-invalidator-types-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-all-invalidator-types-expected.txt
index 2e259e2d..dd7167391 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-style/timeline-style-recalc-all-invalidator-types-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-all-invalidator-types-expected.txt
@@ -7,7 +7,7 @@
 Running: testClassName
 [
     {
-        cause : {reason: Element has pending invalidation list, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.html:9}
+        cause : {reason: Element has pending invalidation list, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.html:9}
         changedAttribute : undefined
         changedClass : "red"
         changedId : undefined
@@ -18,7 +18,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Element has pending invalidation list, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.html:10}
+        cause : {reason: Element has pending invalidation list, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.html:10}
         changedAttribute : undefined
         changedClass : "red"
         changedId : undefined
@@ -35,7 +35,7 @@
 Running: testId
 [
     {
-        cause : {reason: Element has pending invalidation list, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.html:25}
+        cause : {reason: Element has pending invalidation list, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.html:25}
         changedAttribute : undefined
         changedClass : undefined
         changedId : "testElementFour"
@@ -46,7 +46,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Element has pending invalidation list, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.html:26}
+        cause : {reason: Element has pending invalidation list, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.html:26}
         changedAttribute : undefined
         changedClass : undefined
         changedId : "testElementFive"
@@ -61,7 +61,7 @@
 Running: testStyleAttributeChange
 [
     {
-        cause : {reason: StyleSheetChange, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.html:33}
+        cause : {reason: StyleSheetChange, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.html:33}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
@@ -72,7 +72,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: StyleSheetChange, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.html:34}
+        cause : {reason: StyleSheetChange, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.html:34}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
@@ -87,7 +87,7 @@
 Running: testAttributeChange
 [
     {
-        cause : {reason: Attribute, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.html:41}
+        cause : {reason: Attribute, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.html:41}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
@@ -98,7 +98,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Attribute, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.html:42}
+        cause : {reason: Attribute, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.html:42}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
@@ -109,7 +109,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Element has pending invalidation list, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.html:41}
+        cause : {reason: Element has pending invalidation list, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.html:41}
         changedAttribute : "dir"
         changedClass : undefined
         changedId : undefined
@@ -120,7 +120,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Element has pending invalidation list, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.html:42}
+        cause : {reason: Element has pending invalidation list, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.html:42}
         changedAttribute : "dir"
         changedClass : undefined
         changedId : undefined
@@ -135,7 +135,7 @@
 Running: testPseudoChange
 [
     {
-        cause : {reason: PseudoClass, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.html:51}
+        cause : {reason: PseudoClass, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.html:51}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.html
similarity index 96%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.html
index 574b46fb..500bc3c 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.html
@@ -1,8 +1,8 @@
 <!DOCTYPE HTML>
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 function changeClassNameAndDisplay()
 {
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-style/timeline-style-recalc-with-invalidations-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidations-expected.txt
similarity index 76%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-style/timeline-style-recalc-with-invalidations-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidations-expected.txt
index f5b2caca..b5d415d4 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-style/timeline-style-recalc-with-invalidations-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidations-expected.txt
@@ -8,7 +8,7 @@
 Running: testLocalFrame
 first recalc style invalidations[
     {
-        cause : {reason: Inline CSS style declaration was mutated, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-with-invalidations.html:9}
+        cause : {reason: Inline CSS style declaration was mutated, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidations.html:9}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
@@ -19,7 +19,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Inline CSS style declaration was mutated, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-with-invalidations.html:10}
+        cause : {reason: Inline CSS style declaration was mutated, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidations.html:10}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
@@ -34,7 +34,7 @@
 Running: multipleStyleRecalcs
 first recalc style invalidations[
     {
-        cause : {reason: Inline CSS style declaration was mutated, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-with-invalidations.html:21}
+        cause : {reason: Inline CSS style declaration was mutated, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidations.html:21}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
@@ -47,7 +47,7 @@
 ]
 second recalc style invalidations[
     {
-        cause : {reason: Inline CSS style declaration was mutated, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-with-invalidations.html:23}
+        cause : {reason: Inline CSS style declaration was mutated, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidations.html:23}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
@@ -58,7 +58,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Inline CSS style declaration was mutated, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-with-invalidations.html:24}
+        cause : {reason: Inline CSS style declaration was mutated, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidations.html:24}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
@@ -71,7 +71,7 @@
 ]
 third recalc style invalidations[
     {
-        cause : {reason: Inline CSS style declaration was mutated, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-with-invalidations.html:26}
+        cause : {reason: Inline CSS style declaration was mutated, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidations.html:26}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
@@ -82,7 +82,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Inline CSS style declaration was mutated, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-with-invalidations.html:27}
+        cause : {reason: Inline CSS style declaration was mutated, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidations.html:27}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
@@ -93,7 +93,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Inline CSS style declaration was mutated, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-with-invalidations.html:28}
+        cause : {reason: Inline CSS style declaration was mutated, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidations.html:28}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
@@ -108,7 +108,7 @@
 Running: testSubframe
 first recalc style invalidations[
     {
-        cause : {reason: Inline CSS style declaration was mutated, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-with-invalidations.html:35}
+        cause : {reason: Inline CSS style declaration was mutated, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidations.html:35}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
@@ -119,7 +119,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Inline CSS style declaration was mutated, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-with-invalidations.html:36}
+        cause : {reason: Inline CSS style declaration was mutated, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidations.html:36}
         changedAttribute : undefined
         changedClass : undefined
         changedId : undefined
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-style/timeline-style-recalc-with-invalidations.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidations.html
similarity index 95%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-style/timeline-style-recalc-with-invalidations.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidations.html
index 428fc4a..669b432 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-style/timeline-style-recalc-with-invalidations.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidations.html
@@ -1,8 +1,8 @@
 <!DOCTYPE HTML>
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 function changeStylesAndDisplay()
 {
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations-expected.txt
similarity index 75%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations-expected.txt
index 6f5f569..4de5bf4 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations-expected.txt
@@ -8,7 +8,7 @@
 Running: testLocalFrame
 first recalculate styles[
     {
-        cause : {reason: Element has pending invalidation list, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:9}
+        cause : {reason: Element has pending invalidation list, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:9}
         changedAttribute : undefined
         changedClass : "red"
         changedId : undefined
@@ -19,7 +19,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Element has pending invalidation list, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:10}
+        cause : {reason: Element has pending invalidation list, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:10}
         changedAttribute : undefined
         changedClass : "red"
         changedId : undefined
@@ -34,7 +34,7 @@
 Running: multipleStyleRecalcs
 first recalculate styles[
     {
-        cause : {reason: Element has pending invalidation list, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:20}
+        cause : {reason: Element has pending invalidation list, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:20}
         changedAttribute : undefined
         changedClass : "green"
         changedId : undefined
@@ -45,7 +45,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Element has pending invalidation list, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:20}
+        cause : {reason: Element has pending invalidation list, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:20}
         changedAttribute : undefined
         changedClass : "red"
         changedId : undefined
@@ -58,7 +58,7 @@
 ]
 second recalculate styles[
     {
-        cause : {reason: Element has pending invalidation list, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:22}
+        cause : {reason: Element has pending invalidation list, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:22}
         changedAttribute : undefined
         changedClass : "blue"
         changedId : undefined
@@ -69,7 +69,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Element has pending invalidation list, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:22}
+        cause : {reason: Element has pending invalidation list, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:22}
         changedAttribute : undefined
         changedClass : "green"
         changedId : undefined
@@ -80,7 +80,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Element has pending invalidation list, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:23}
+        cause : {reason: Element has pending invalidation list, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:23}
         changedAttribute : undefined
         changedClass : "blue"
         changedId : undefined
@@ -91,7 +91,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Element has pending invalidation list, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:23}
+        cause : {reason: Element has pending invalidation list, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:23}
         changedAttribute : undefined
         changedClass : "red"
         changedId : undefined
@@ -104,7 +104,7 @@
 ]
 third recalculate styles[
     {
-        cause : {reason: Element has pending invalidation list, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:25}
+        cause : {reason: Element has pending invalidation list, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:25}
         changedAttribute : undefined
         changedClass : "snow"
         changedId : undefined
@@ -115,7 +115,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Element has pending invalidation list, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:25}
+        cause : {reason: Element has pending invalidation list, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:25}
         changedAttribute : undefined
         changedClass : "blue"
         changedId : undefined
@@ -126,7 +126,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Element has pending invalidation list, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:26}
+        cause : {reason: Element has pending invalidation list, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:26}
         changedAttribute : undefined
         changedClass : "snow"
         changedId : undefined
@@ -137,7 +137,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Element has pending invalidation list, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:26}
+        cause : {reason: Element has pending invalidation list, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:26}
         changedAttribute : undefined
         changedClass : "blue"
         changedId : undefined
@@ -148,7 +148,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Element has pending invalidation list, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:27}
+        cause : {reason: Element has pending invalidation list, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:27}
         changedAttribute : undefined
         changedClass : "snow"
         changedId : undefined
@@ -163,7 +163,7 @@
 Running: testSubframe
 first recalculate styles[
     {
-        cause : {reason: Element has pending invalidation list, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:38}
+        cause : {reason: Element has pending invalidation list, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:38}
         changedAttribute : undefined
         changedClass : "green"
         changedId : undefined
@@ -176,7 +176,7 @@
 ]
 second recalculate styles[
     {
-        cause : {reason: Element has pending invalidation list, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:40}
+        cause : {reason: Element has pending invalidation list, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:40}
         changedAttribute : undefined
         changedClass : "blue"
         changedId : undefined
@@ -187,7 +187,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Element has pending invalidation list, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:40}
+        cause : {reason: Element has pending invalidation list, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:40}
         changedAttribute : undefined
         changedClass : "green"
         changedId : undefined
@@ -198,7 +198,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Element has pending invalidation list, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:41}
+        cause : {reason: Element has pending invalidation list, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:41}
         changedAttribute : undefined
         changedClass : "blue"
         changedId : undefined
@@ -211,7 +211,7 @@
 ]
 third recalculate styles[
     {
-        cause : {reason: Element has pending invalidation list, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:43}
+        cause : {reason: Element has pending invalidation list, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:43}
         changedAttribute : undefined
         changedClass : "snow"
         changedId : undefined
@@ -222,7 +222,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Element has pending invalidation list, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:43}
+        cause : {reason: Element has pending invalidation list, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:43}
         changedAttribute : undefined
         changedClass : "blue"
         changedId : undefined
@@ -233,7 +233,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Element has pending invalidation list, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:44}
+        cause : {reason: Element has pending invalidation list, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:44}
         changedAttribute : undefined
         changedClass : "snow"
         changedId : undefined
@@ -244,7 +244,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Element has pending invalidation list, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:44}
+        cause : {reason: Element has pending invalidation list, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:44}
         changedAttribute : undefined
         changedClass : "blue"
         changedId : undefined
@@ -255,7 +255,7 @@
         type : "StyleRecalcInvalidationTracking"
     }
     {
-        cause : {reason: Element has pending invalidation list, stackTrace: .../inspector/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:45}
+        cause : {reason: Element has pending invalidation list, stackTrace: http://127.0.0.1:8000/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html:45}
         changedAttribute : undefined
         changedClass : "snow"
         changedId : undefined
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html
similarity index 96%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html
index 8eeb233..f6cd9d6d 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html
@@ -1,8 +1,8 @@
 <!DOCTYPE HTML>
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 function changeStylesAndDisplay()
 {
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-time/timeline-time-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-time-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-time/timeline-time-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-time-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-time/timeline-time-stamp-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-time-stamp-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-time/timeline-time-stamp-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-time-stamp-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-time/timeline-time-stamp.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-time-stamp.html
similarity index 72%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-time/timeline-time-stamp.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-time-stamp.html
index 3c7c5da5..a1ad911 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-time/timeline-time-stamp.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-time-stamp.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 
 function performActions()
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-time/timeline-time.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-time.html
similarity index 93%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-time/timeline-time.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-time.html
index ace62be..8de8132 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-time/timeline-time.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-time.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 
 testRunner.setDumpConsoleMessages(false);
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-time/timeline-timer-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-timer-expected.txt
similarity index 93%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-time/timeline-timer-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-timer-expected.txt
index ec5b64b..893b3b9 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-time/timeline-timer-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-timer-expected.txt
@@ -89,7 +89,7 @@
         functionName : "intervalTimerWork"
         lineNumber : <number>
         scriptId : <string>
-        url : .../inspector/tracing/timeline-time/timeline-timer.html
+        url : http://127.0.0.1:8000/devtools/tracing/timeline-time/timeline-timer.html
     }
     endTime : <number>
     frameId : <string>
@@ -103,7 +103,7 @@
         functionName : "intervalTimerWork"
         lineNumber : <number>
         scriptId : <string>
-        url : .../inspector/tracing/timeline-time/timeline-timer.html
+        url : http://127.0.0.1:8000/devtools/tracing/timeline-time/timeline-timer.html
     }
     endTime : <number>
     frameId : <string>
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-time/timeline-timer-fired-from-eval-call-site-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-timer-fired-from-eval-call-site-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-time/timeline-timer-fired-from-eval-call-site-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-timer-fired-from-eval-call-site-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-time/timeline-timer-fired-from-eval-call-site.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-timer-fired-from-eval-call-site.html
similarity index 91%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-time/timeline-timer-fired-from-eval-call-site.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-timer-fired-from-eval-call-site.html
index ed6e55a..c335002 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-time/timeline-timer-fired-from-eval-call-site.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-timer-fired-from-eval-call-site.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 
 function performActions()
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-time/timeline-timer.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-timer.html
similarity index 88%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-time/timeline-timer.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-timer.html
index 778b1ef..f5d8e1c 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-time/timeline-timer.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-timer.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script>
 
 function performActions()
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-time/timeline-usertiming-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-usertiming-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-time/timeline-usertiming-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-usertiming-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-time/timeline-usertiming.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-usertiming.html
similarity index 94%
rename from third_party/WebKit/LayoutTests/inspector/tracing/timeline-time/timeline-usertiming.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-usertiming.html
index 140bd795..b127652f 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-time/timeline-usertiming.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-usertiming.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/timeline-test.js"></script>
 <script src="../../tracing-test.js"></script>
 <script>
 
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/trace-event-self-time-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/trace-event-self-time-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/trace-event-self-time-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/trace-event-self-time-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/trace-event-self-time.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/trace-event-self-time.html
similarity index 97%
rename from third_party/WebKit/LayoutTests/inspector/tracing/trace-event-self-time.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/trace-event-self-time.html
index caddf0c..7fdda10 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/trace-event-self-time.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/trace-event-self-time.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../inspector/inspector-test.js"></script>
+<script src="../../inspector/timeline-test.js"></script>
 <script>
 function test() {
   var sessionId = '6.23';
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/tracing-timeline-load-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/tracing-timeline-load-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/tracing-timeline-load-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/tracing-timeline-load-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/tracing-timeline-load.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/tracing-timeline-load.html
similarity index 98%
rename from third_party/WebKit/LayoutTests/inspector/tracing/tracing-timeline-load.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/tracing-timeline-load.html
index 1da542b..f1b78aa 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/tracing-timeline-load.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/tracing-timeline-load.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../inspector/inspector-test.js"></script>
+<script src="../../inspector/timeline-test.js"></script>
 <script>
 
 function test() {
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/worker-events-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/worker-events-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/worker-events-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/worker-events-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/worker-events.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/worker-events.html
similarity index 92%
rename from third_party/WebKit/LayoutTests/inspector/tracing/worker-events.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/worker-events.html
index 9233f07..645de68 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/worker-events.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/worker-events.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../inspector/inspector-test.js"></script>
+<script src="../../inspector/timeline-test.js"></script>
 <script>
 
 // Save references to the worker objects to make sure they are not GC'ed.
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/worker-js-frames-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/worker-js-frames-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/worker-js-frames-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/worker-js-frames-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/worker-js-frames.html b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/worker-js-frames.html
similarity index 94%
rename from third_party/WebKit/LayoutTests/inspector/tracing/worker-js-frames.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/tracing/worker-js-frames.html
index 6d21d2d..518198c 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/worker-js-frames.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/worker-js-frames.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../inspector/inspector-test.js"></script>
+<script src="../../inspector/timeline-test.js"></script>
 <script>
 
 // Save references to the worker objects to make sure they are not GC'ed.
diff --git a/third_party/WebKit/LayoutTests/http/tests/feature-policy-experimental-features/vibrate-allowed-by-container-policy-relocate-and-no-reload-expected.txt b/third_party/WebKit/LayoutTests/http/tests/feature-policy-experimental-features/vibrate-allowed-by-container-policy-relocate-and-no-reload-expected.txt
index aca720b..ce48133 100644
--- a/third_party/WebKit/LayoutTests/http/tests/feature-policy-experimental-features/vibrate-allowed-by-container-policy-relocate-and-no-reload-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/feature-policy-experimental-features/vibrate-allowed-by-container-policy-relocate-and-no-reload-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE ERROR: line 4: Error while parsing the 'allow' attribute: 'vibrate' is an invalid feature name.
+CONSOLE WARNING: line 4: Unrecognized feature: 'vibrate'.
 This is a testharness.js-based test.
 FAIL Iframe navigated itself to a new origin, vibrate is disabled by container policy. assert_false: navigator.vibrate(): expected false got true
 Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/http/tests/feature-policy-experimental-features/vibrate-disabled-expected.txt b/third_party/WebKit/LayoutTests/http/tests/feature-policy-experimental-features/vibrate-disabled-expected.txt
index ae7093e98..a28d63b 100644
--- a/third_party/WebKit/LayoutTests/http/tests/feature-policy-experimental-features/vibrate-disabled-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/feature-policy-experimental-features/vibrate-disabled-expected.txt
@@ -1,3 +1,4 @@
+CONSOLE ERROR: Error with Feature-Policy header: Unrecognized feature: 'vibrate'.
 This is a testharness.js-based test.
 FAIL Navigator.vibrate disabled on URL: resources/feature-policy-vibrate.html assert_false: navigator.vibrate(): expected false got true
 FAIL Navigator.vibrate disabled on URL: http://localhost:8000/feature-policy-experimental-features/resources/feature-policy-vibrate.html assert_false: navigator.vibrate(): expected false got true
diff --git a/third_party/WebKit/LayoutTests/http/tests/feature-policy-experimental-features/vibrate-disabled.php b/third_party/WebKit/LayoutTests/http/tests/feature-policy-experimental-features/vibrate-disabled.php
index 0ffadc6..5d2af309 100644
--- a/third_party/WebKit/LayoutTests/http/tests/feature-policy-experimental-features/vibrate-disabled.php
+++ b/third_party/WebKit/LayoutTests/http/tests/feature-policy-experimental-features/vibrate-disabled.php
@@ -6,7 +6,7 @@
 // This test ensures that navigator.vibrate when disabled may not be called by
 // any iframe.
 
-Header("Feature-Policy: {\"vibrate\": []}");
+Header("Feature-Policy: vibrate 'none'");
 ?>
 
 <!DOCTYPE html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/feature-policy-experimental-features/vibrate-enabledforall.php b/third_party/WebKit/LayoutTests/http/tests/feature-policy-experimental-features/vibrate-enabledforall.php
index 1885bad..8005a6d 100644
--- a/third_party/WebKit/LayoutTests/http/tests/feature-policy-experimental-features/vibrate-enabledforall.php
+++ b/third_party/WebKit/LayoutTests/http/tests/feature-policy-experimental-features/vibrate-enabledforall.php
@@ -6,7 +6,7 @@
 // This test ensures that navigator.vibrate when enabled for all works across
 // origins.
 
-Header("Feature-Policy: {\"vibrate\": [\"*\"]}");
+Header("Feature-Policy: vibrate *");
 ?>
 
 <!DOCTYPE html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/feature-policy-experimental-features/vibrate-enabledforself-expected.txt b/third_party/WebKit/LayoutTests/http/tests/feature-policy-experimental-features/vibrate-enabledforself-expected.txt
index bc96a66..dae4d79 100644
--- a/third_party/WebKit/LayoutTests/http/tests/feature-policy-experimental-features/vibrate-enabledforself-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/feature-policy-experimental-features/vibrate-enabledforself-expected.txt
@@ -1,3 +1,4 @@
+CONSOLE ERROR: Error with Feature-Policy header: Unrecognized feature: 'vibrate'.
 This is a testharness.js-based test.
 PASS Navigator.vibrate enabled for self on URL: resources/feature-policy-vibrate.html
 FAIL Navigator.vibrate enabled for self on URL: http://localhost:8000/feature-policy-experimental-features/resources/feature-policy-vibrate.html assert_false: navigator.vibrate(): expected false got true
diff --git a/third_party/WebKit/LayoutTests/http/tests/feature-policy-experimental-features/vibrate-enabledforself.php b/third_party/WebKit/LayoutTests/http/tests/feature-policy-experimental-features/vibrate-enabledforself.php
index 6cf8a22..9c91c7d 100644
--- a/third_party/WebKit/LayoutTests/http/tests/feature-policy-experimental-features/vibrate-enabledforself.php
+++ b/third_party/WebKit/LayoutTests/http/tests/feature-policy-experimental-features/vibrate-enabledforself.php
@@ -6,7 +6,7 @@
 // This test ensures that navigator.vibrate when enabled for self only works on
 // the same origin.
 
-Header("Feature-Policy: {\"vibrate\": [\"self\"]}");
+Header("Feature-Policy: vibrate 'self'");
 ?>
 
 <!DOCTYPE html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/feature-policy/fullscreen-disabled.php b/third_party/WebKit/LayoutTests/http/tests/feature-policy/fullscreen-disabled.php
index 82ac79bc..784cdb74 100644
--- a/third_party/WebKit/LayoutTests/http/tests/feature-policy/fullscreen-disabled.php
+++ b/third_party/WebKit/LayoutTests/http/tests/feature-policy/fullscreen-disabled.php
@@ -6,7 +6,7 @@
 // This test ensures that fullscreen feature when disabled may not be called by
 // any iframe even when allowfullscreen is set.
 
-Header("Feature-Policy: {\"fullscreen\": []}");
+Header("Feature-Policy: fullscreen 'none'");
 ?>
 
 <!DOCTYPE html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/feature-policy/fullscreen-enabledforall.php b/third_party/WebKit/LayoutTests/http/tests/feature-policy/fullscreen-enabledforall.php
index 658eb9c..607f2cd 100644
--- a/third_party/WebKit/LayoutTests/http/tests/feature-policy/fullscreen-enabledforall.php
+++ b/third_party/WebKit/LayoutTests/http/tests/feature-policy/fullscreen-enabledforall.php
@@ -7,7 +7,7 @@
 // origins regardless of whether allowfullscreen is set. (Feature policy header
 // takes precedence over the absence of allowfullscreen.)
 
-Header("Feature-Policy: {\"fullscreen\": [\"*\"]}");
+Header("Feature-Policy: fullscreen: *");
 ?>
 
 <!DOCTYPE html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/feature-policy/fullscreen-enabledforself.php b/third_party/WebKit/LayoutTests/http/tests/feature-policy/fullscreen-enabledforself.php
index badaab0..48642870 100644
--- a/third_party/WebKit/LayoutTests/http/tests/feature-policy/fullscreen-enabledforself.php
+++ b/third_party/WebKit/LayoutTests/http/tests/feature-policy/fullscreen-enabledforself.php
@@ -7,7 +7,7 @@
 // in the same orgin but not cross origins when allowfullscreen is set. No
 // iframe may call it when allowfullscreen is not set.
 
-Header("Feature-Policy: {\"fullscreen\": [\"self\"]}");
+Header("Feature-Policy: fullscreen 'self'");
 ?>
 
 <!DOCTYPE html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/feature-policy/payment-disabled.php b/third_party/WebKit/LayoutTests/http/tests/feature-policy/payment-disabled.php
index 1851985..22aa7dba 100644
--- a/third_party/WebKit/LayoutTests/http/tests/feature-policy/payment-disabled.php
+++ b/third_party/WebKit/LayoutTests/http/tests/feature-policy/payment-disabled.php
@@ -6,7 +6,7 @@
 // This test ensures that payment feature when disabled may not be called by
 // any iframe even when allowpaymentrequest is set.
 
-Header("Feature-Policy: {\"payment\": []}");
+Header("Feature-Policy: payment 'none'");
 ?>
 
 <!DOCTYPE html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/feature-policy/payment-enabledforall.php b/third_party/WebKit/LayoutTests/http/tests/feature-policy/payment-enabledforall.php
index 1de5862a..c6e9a68 100644
--- a/third_party/WebKit/LayoutTests/http/tests/feature-policy/payment-enabledforall.php
+++ b/third_party/WebKit/LayoutTests/http/tests/feature-policy/payment-enabledforall.php
@@ -7,7 +7,7 @@
 // all origins regardless whether allowpaymentrequest is set. (Feature policy
 // header takes precedence over the absence of allowpaymentrequest.)
 
-Header("Feature-Policy: {\"payment\": [\"*\"]}");
+Header("Feature-Policy: payment *");
 ?>
 
 <!DOCTYPE html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/feature-policy/payment-enabledforself.php b/third_party/WebKit/LayoutTests/http/tests/feature-policy/payment-enabledforself.php
index e46d779..0142031 100644
--- a/third_party/WebKit/LayoutTests/http/tests/feature-policy/payment-enabledforself.php
+++ b/third_party/WebKit/LayoutTests/http/tests/feature-policy/payment-enabledforself.php
@@ -7,7 +7,7 @@
 // the same origin or when allowpaymentrequest is set. No cross-origin iframe
 // may call it when allowpaymentrequest is not set.
 
-Header("Feature-Policy: {\"payment\": [\"self\"]}");
+Header("Feature-Policy: payment 'self'");
 ?>
 
 <!DOCTYPE html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/cachestorage/read-cached-response.js b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/cachestorage/read-cached-response.js
index 732ce69..d638797d 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/cachestorage/read-cached-response.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/cachestorage/read-cached-response.js
@@ -3,15 +3,15 @@
       'resources/service-worker.html',
       `Tests reading cached response from the protocol.`);
 
-  async function dumpResponse(cacheId, path) {
-    var {error, result} = await dp.CacheStorage.requestCachedResponse({cacheId, requestURL: path});
+  async function dumpResponse(cacheId, entry) {
+    var {error, result} = await dp.CacheStorage.requestCachedResponse({cacheId, requestURL: entry ? entry.requestURL : null});
     if (error) {
       testRunner.log(`Error: ${error.message} ${error.data || ""}`);
       return;
     }
-    var response = result.response;
-    testRunner.log(response.headers["Content-Type"]);
-    testRunner.log("Type of body: " + (typeof response.body));
+    var header = entry.responseHeaders.find(header => header.name.toLowerCase() === 'content-type');
+    testRunner.log(header ? header.value : '');
+    testRunner.log("Type of body: " + (typeof result.response.body));
   }
 
   async function waitForServiceWorkerActivation() {
@@ -30,10 +30,11 @@
   var {result} = await dp.CacheStorage.requestCacheNames({securityOrigin: "http://127.0.0.1:8000"});
   var cacheId = result.caches[0].cacheId;
   result = await dp.CacheStorage.requestEntries({cacheId, skipCount: 0, pageSize: 5});
-  var requests = result.result.cacheDataEntries.map(entry => entry.request).sort();
+  var entries = result.result.cacheDataEntries;
+  entries.sort((a, b) => a.requestURL.localeCompare(b.requestURL));
   testRunner.log("Cached requests:");
 
-  for (var entry of requests)
+  for (var entry of entries)
     await dumpResponse(cacheId, entry);
 
   testRunner.log('Trying without specifying all the arguments:')
@@ -41,9 +42,9 @@
   testRunner.log('Trying without specifying the request path:')
   await dumpResponse(cacheId, null);
   testRunner.log('Trying with non existant cache:')
-  await dumpResponse("bogus", requests[0]);
+  await dumpResponse("bogus", entries[0]);
   testRunner.log('Trying with non existant request path:')
-  await dumpResponse(cacheId, "http://localhost:8080/bogus");
+  await dumpResponse(cacheId, {requestURL: "http://localhost:8080/bogus"});
 
   testRunner.completeTest()
 });
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/cache-storage/cache-storage-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/cache-storage/cache-storage-test.js
index e394ca9..d7daa8b 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/cache-storage/cache-storage-test.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/cache-storage/cache-storage-test.js
@@ -39,7 +39,7 @@
 
         await promise;
 
-        if (view._entries.length == 0) {
+        if (view._entriesForTest.length == 0) {
             InspectorTest.addResult("        (cache empty)");
             continue;
         }
@@ -99,12 +99,12 @@
 
         await promise;
 
-        var entry = view._entries.find(entry => entry.request === optionalEntry);
+        var entry = view._entriesForTest.find(entry => entry.requestURL === optionalEntry);
         if (!entry) {
             throw "Error: Could not find cache entry to delete: " + optionalEntry;
             return;
         }
-        await view._model.deleteCacheEntry(view._cache, entry.request);
+        await view._model.deleteCacheEntry(view._cache, entry.requestURL);
         return;
     }
     throw "Error: Could not find CacheStorage cache " + cacheName;
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/timeline-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/timeline-test.js
index 5ad1ff5..21b013e6 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/timeline-test.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/timeline-test.js
@@ -42,6 +42,7 @@
     allottedMilliseconds: "formatAsTypeName",
     timedOut: "formatAsTypeName",
     networkTime: "formatAsTypeName",
+    timing: "formatAsTypeName",
 };
 
 InspectorTest.InvalidationFormatters = {
diff --git a/third_party/WebKit/LayoutTests/http/tests/resources/permissions-helper.js b/third_party/WebKit/LayoutTests/http/tests/resources/permissions-helper.js
index f3bc68e..286ff12 100644
--- a/third_party/WebKit/LayoutTests/http/tests/resources/permissions-helper.js
+++ b/third_party/WebKit/LayoutTests/http/tests/resources/permissions-helper.js
@@ -25,6 +25,8 @@
         return {name: "geolocation"};
       case "background-sync":
         return {name: "background-sync"};
+      case "accessibility-events":
+        return {name: "accessibility-events"};
       default:
         throw "Invalid permission name provided";
     }
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/access-control-preflight-request-header-lowercase-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/access-control-preflight-request-header-lowercase-expected.txt
deleted file mode 100644
index d1a5af4..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/access-control-preflight-request-header-lowercase-expected.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Test for bug 75089: Access-Control-Request-Headers values should be lowercase.
-
-PASS
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/access-control-preflight-request-header-lowercase.html b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/access-control-preflight-request-header-lowercase.html
deleted file mode 100644
index 625f731..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/access-control-preflight-request-header-lowercase.html
+++ /dev/null
@@ -1,33 +0,0 @@
-<html>
-<body>
-<p>Test for bug 75089: Access-Control-Request-Headers values should be lowercase.</p>
-<script>
-if (window.testRunner) {
-    testRunner.dumpAsText();
-    testRunner.waitUntilDone();
-}
-
-function sendRequest()
-{
-    var xhr = new XMLHttpRequest;
-    xhr.open("GET", "http://localhost:8000/xmlhttprequest/resources/access-control-preflight-request-header-lowercase.php");
-    xhr.setRequestHeader("X-Custom-Header", "foobar");
-    xhr.onerror = function() {
-        document.body.appendChild(document.createTextNode("FAIL: onerror called"));
-        if (window.testRunner)
-            testRunner.notifyDone();
-    }
-
-    xhr.onreadystatechange=function() {
-        if (xhr.readyState==4) {
-            document.body.appendChild(document.createTextNode(xhr.responseText));
-            if (window.testRunner)
-                testRunner.notifyDone();
-        }
-    }
-    xhr.send();
-}
-sendRequest();
-</script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/resources/access-control-preflight-request-header-lowercase.php b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/resources/access-control-preflight-request-header-lowercase.php
deleted file mode 100644
index b33f1c2..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/resources/access-control-preflight-request-header-lowercase.php
+++ /dev/null
@@ -1,17 +0,0 @@
-<?php
-header("Access-Control-Allow-Origin: *");
-header("Access-Control-Max-Age: 0");
-
-if ($_SERVER["REQUEST_METHOD"] == "OPTIONS") {
-    // Split the Access-Control-Request-header value based on the token.
-    $accessControlRequestHeaderValues = explode(", ", $_SERVER["HTTP_ACCESS_CONTROL_REQUEST_HEADERS"]);
-    if (in_array("x-custom-header", $accessControlRequestHeaderValues)) // Case-sensitive comparison to make sure that browser sends the value in lowercase.
-        header("Access-Control-Allow-Headers: X-Custom-Header");  // Add "Access-Control-Allow-Headers: X-Custom-Header" to "OPTIONS" response.
-
-} else if ($_SERVER["REQUEST_METHOD"] == "GET") {
-    if (isset($_SERVER["HTTP_X_CUSTOM_HEADER"]))
-        echo "PASS";
-    else
-        echo "FAIL";
-}
-?>
diff --git a/third_party/WebKit/LayoutTests/inspector/layers/layer-canvas-log.html b/third_party/WebKit/LayoutTests/inspector/layers/layer-canvas-log.html
index fba4602..bf76d2f 100644
--- a/third_party/WebKit/LayoutTests/inspector/layers/layer-canvas-log.html
+++ b/third_party/WebKit/LayoutTests/inspector/layers/layer-canvas-log.html
@@ -22,7 +22,7 @@
 <body onload="runTest()">
 <div id="a" style="transform: translateZ(0px); background-color:blue; width:100px; height:100px;">
     <div style="width:50px; height:50px; background-color:red;"></div>
-    <img src="../tracing/resources/test.png">
+    <img src="resources/test.png">
     <svg>
         <rect x="0" y="0" width="10" height="10" style="opacity:0.5"/>
     </svg>
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/resources/test.png b/third_party/WebKit/LayoutTests/inspector/layers/resources/test.png
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/resources/test.png
rename to third_party/WebKit/LayoutTests/inspector/layers/resources/test.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/decode-resize-expected.txt b/third_party/WebKit/LayoutTests/inspector/tracing/decode-resize-expected.txt
deleted file mode 100644
index 556b484..0000000
--- a/third_party/WebKit/LayoutTests/inspector/tracing/decode-resize-expected.txt
+++ /dev/null
@@ -1,66 +0,0 @@
-Tests the instrumentation of a DecodeImage and ResizeImage events
-
-event: Decode Image
-imageURL: .../inspector/tracing/resources/big.png
-backendNodeId: present
-event: Decode Image
-imageURL: .../inspector/tracing/resources/big.png?background
-backendNodeId: present
-event: Decode Image
-imageURL: .../inspector/tracing/resources/big.png?border
-backendNodeId: present
-event: Decode Image
-imageURL: .../inspector/tracing/resources/test.bmp
-backendNodeId: present
-event: Decode Image
-imageURL: .../inspector/tracing/resources/test.bmp?background
-backendNodeId: present
-event: Decode Image
-imageURL: .../inspector/tracing/resources/test.bmp?border
-backendNodeId: present
-event: Decode Image
-imageURL: .../inspector/tracing/resources/test.gif
-backendNodeId: present
-event: Decode Image
-imageURL: .../inspector/tracing/resources/test.gif?background
-backendNodeId: present
-event: Decode Image
-imageURL: .../inspector/tracing/resources/test.gif?border
-backendNodeId: present
-event: Decode Image
-imageURL: .../inspector/tracing/resources/test.ico
-backendNodeId: present
-event: Decode Image
-imageURL: .../inspector/tracing/resources/test.ico?background
-backendNodeId: present
-event: Decode Image
-imageURL: .../inspector/tracing/resources/test.ico?border
-backendNodeId: present
-event: Decode Image
-imageURL: .../inspector/tracing/resources/test.jpg
-backendNodeId: present
-event: Decode Image
-imageURL: .../inspector/tracing/resources/test.jpg?background
-backendNodeId: present
-event: Decode Image
-imageURL: .../inspector/tracing/resources/test.jpg?border
-backendNodeId: present
-event: Decode Image
-imageURL: .../inspector/tracing/resources/test.png
-backendNodeId: present
-event: Decode Image
-imageURL: .../inspector/tracing/resources/test.png?background
-backendNodeId: present
-event: Decode Image
-imageURL: .../inspector/tracing/resources/test.png?border
-backendNodeId: present
-event: Decode Image
-imageURL: .../inspector/tracing/resources/test.webp
-backendNodeId: present
-event: Decode Image
-imageURL: .../inspector/tracing/resources/test.webp?background
-backendNodeId: present
-event: Decode Image
-imageURL: .../inspector/tracing/resources/test.webp?border
-backendNodeId: present
-
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/fix_all b/third_party/WebKit/LayoutTests/inspector/tracing/fix_all
deleted file mode 100755
index 511303fd..0000000
--- a/third_party/WebKit/LayoutTests/inspector/tracing/fix_all
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/bash
-
-
-for f in $*
-do
-    echo "Fixing $f"
-    sed -i -f fix_path $f
-done
-
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/fix_path b/third_party/WebKit/LayoutTests/inspector/tracing/fix_path
deleted file mode 100644
index d1ed081..0000000
--- a/third_party/WebKit/LayoutTests/inspector/tracing/fix_path
+++ /dev/null
@@ -1,3 +0,0 @@
-s/\"\.\.\/\./"./g
-
-
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/animated-gif-transformed-offscreen-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/animated-gif-transformed-offscreen-expected.txt
index 3ce4dc4..8d493bb 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/animated-gif-transformed-offscreen-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/animated-gif-transformed-offscreen-expected.txt
@@ -11,6 +11,12 @@
       "position": [8, 8],
       "bounds": [2000, 2000],
       "drawsContent": true,
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/child-of-sub-pixel-offset-composited-layer-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/child-of-sub-pixel-offset-composited-layer-expected.txt
index 3b84a3b..018fa71b 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/child-of-sub-pixel-offset-composited-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/child-of-sub-pixel-offset-composited-layer-expected.txt
@@ -9,7 +9,6 @@
     {
       "name": "LayoutBlockFlow (positioned) DIV class='container'",
       "position": [101, 100],
-      "transformOrigin": [0, 0],
       "bounds": [14, 14],
       "drawsContent": true,
       "backgroundColor": "#FF0000",
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/clip-path-constant-repaint-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/clip-path-constant-repaint-expected.txt
index f4828c5..631cc0f2 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/clip-path-constant-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/clip-path-constant-repaint-expected.txt
@@ -13,6 +13,12 @@
       "drawsContent": true,
       "backfaceVisibility": "hidden",
       "backgroundColor": "#FF0000E6",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/composited-overflow-with-borderbox-background-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/composited-overflow-with-borderbox-background-expected.txt
index accfe01..4df77ac 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/composited-overflow-with-borderbox-background-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/composited-overflow-with-borderbox-background-expected.txt
@@ -11,7 +11,6 @@
       "position": [8, 8],
       "bounds": [220, 220],
       "contentsOpaque": true,
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#008000",
       "paintInvalidations": [
@@ -24,12 +23,12 @@
     },
     {
       "name": "Scrolling Layer",
-      "position": [10, 10],
-      "bounds": [185, 185],
-      "shouldFlattenTransform": false
+      "position": [18, 18],
+      "bounds": [185, 185]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [18, 18],
       "bounds": [185, 300],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -43,21 +42,22 @@
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 8],
       "bounds": [220, 220]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [10, 195],
+      "position": [18, 203],
       "bounds": [185, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [195, 10],
+      "position": [203, 18],
       "bounds": [15, 185]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [195, 195],
+      "position": [203, 203],
       "bounds": [15, 15],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/composited-overflow-with-local-background-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/composited-overflow-with-local-background-expected.txt
index dce7761..de043d5d 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/composited-overflow-with-local-background-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/composited-overflow-with-local-background-expected.txt
@@ -10,7 +10,6 @@
       "name": "LayoutBlockFlow DIV id='scroller'",
       "position": [8, 8],
       "bounds": [200, 200],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#008000",
       "paintInvalidations": [
@@ -23,11 +22,12 @@
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [185, 185],
-      "shouldFlattenTransform": false
+      "position": [8, 8],
+      "bounds": [185, 185]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 8],
       "bounds": [185, 300],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -41,21 +41,22 @@
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 8],
       "bounds": [200, 200]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [0, 185],
+      "position": [8, 193],
       "bounds": [185, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [185, 0],
+      "position": [193, 8],
       "bounds": [15, 185]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [185, 185],
+      "position": [193, 193],
       "bounds": [15, 15],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/composited-overflow-with-negative-offset-outline-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/composited-overflow-with-negative-offset-outline-expected.txt
index a42bd28..91161ddf 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/composited-overflow-with-negative-offset-outline-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/composited-overflow-with-negative-offset-outline-expected.txt
@@ -10,7 +10,6 @@
       "name": "LayoutBlockFlow DIV id='scroller'",
       "position": [8, 8],
       "bounds": [200, 200],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "paintInvalidations": [
         {
@@ -22,36 +21,39 @@
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [185, 185],
-      "shouldFlattenTransform": false
+      "position": [8, 8],
+      "bounds": [185, 185]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 8],
       "bounds": [185, 300],
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 8],
       "bounds": [200, 200]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [0, 185],
+      "position": [8, 193],
       "bounds": [185, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [185, 0],
+      "position": [193, 8],
       "bounds": [15, 185]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [185, 185],
+      "position": [193, 193],
       "bounds": [15, 15],
       "drawsContent": true
     },
     {
       "name": "Decoration Layer",
+      "position": [8, 8],
       "bounds": [200, 200],
       "drawsContent": true,
       "paintInvalidations": [
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/composited-vertical-rl-overflow-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/composited-vertical-rl-overflow-expected.txt
index 989ebefb..1d156a9f2 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/composited-vertical-rl-overflow-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/composited-vertical-rl-overflow-expected.txt
@@ -9,7 +9,6 @@
     {
       "name": "LayoutBlockFlow (positioned) DIV id='div'",
       "position": [50, 100],
-      "transformOrigin": [100, 50],
       "bounds": [150, 100],
       "drawsContent": true,
       "backgroundColor": "#0000FF",
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/background-attachment-local-composited-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/background-attachment-local-composited-expected.txt
index 6e54633..153d6539 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/background-attachment-local-composited-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/background-attachment-local-composited-expected.txt
@@ -10,17 +10,17 @@
       "name": "LayoutBlockFlow DIV id='container'",
       "position": [8, 8],
       "bounds": [400, 400],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#0000FF"
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [400, 400],
-      "shouldFlattenTransform": false
+      "position": [8, 8],
+      "bounds": [400, 400]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 8],
       "bounds": [400, 2000],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -34,17 +34,18 @@
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 8],
       "bounds": [400, 400]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [0, 400],
+      "position": [8, 408],
       "bounds": [400, 0],
       "drawsContent": true
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [400, 0],
+      "position": [408, 8],
       "bounds": [0, 400],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/background-attachment-local-equivalent-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/background-attachment-local-equivalent-expected.txt
index 6e54633..153d6539 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/background-attachment-local-equivalent-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/background-attachment-local-equivalent-expected.txt
@@ -10,17 +10,17 @@
       "name": "LayoutBlockFlow DIV id='container'",
       "position": [8, 8],
       "bounds": [400, 400],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#0000FF"
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [400, 400],
-      "shouldFlattenTransform": false
+      "position": [8, 8],
+      "bounds": [400, 400]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 8],
       "bounds": [400, 2000],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -34,17 +34,18 @@
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 8],
       "bounds": [400, 400]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [0, 400],
+      "position": [8, 408],
       "bounds": [400, 0],
       "drawsContent": true
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [400, 0],
+      "position": [408, 8],
       "bounds": [0, 400],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/clipping-should-not-repaint-composited-descendants-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/clipping-should-not-repaint-composited-descendants-expected.txt
index 5231a06a..3e146f6 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/clipping-should-not-repaint-composited-descendants-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/clipping-should-not-repaint-composited-descendants-expected.txt
@@ -13,11 +13,12 @@
     },
     {
       "name": "Child Containment Layer",
+      "position": [108, 108],
       "bounds": [100, 100]
     },
     {
       "name": "LayoutBlockFlow DIV class='clipped-composited-child'",
-      "position": [-100, -100],
+      "position": [8, 8],
       "bounds": [252, 252],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -30,11 +31,12 @@
     },
     {
       "name": "Child Containment Layer",
+      "position": [108, 408],
       "bounds": [100, 100]
     },
     {
       "name": "LayoutBlockFlow DIV class='clipped-composited-child'",
-      "position": [-100, -100],
+      "position": [8, 308],
       "bounds": [252, 252],
       "contentsOpaque": true,
       "drawsContent": true,
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/column-span-under-composited-column-child-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/column-span-under-composited-column-child-expected.txt
index 429c035f..f558a9b3a 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/column-span-under-composited-column-child-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/column-span-under-composited-column-child-expected.txt
@@ -16,7 +16,6 @@
     {
       "name": "LayoutBlockFlow DIV",
       "position": [8, 8],
-      "transformOrigin": [392, 0],
       "contentsOpaque": true
     },
     {
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/composited-float-under-composited-inline-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/composited-float-under-composited-inline-expected.txt
index 353e6353..98bb542 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/composited-float-under-composited-inline-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/composited-float-under-composited-inline-expected.txt
@@ -13,7 +13,7 @@
     },
     {
       "name": "LayoutBlockFlow (relative positioned) (floating) DIV id='float'",
-      "position": [-50, -50],
+      "position": [58, 58],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "drawsContent": true,
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/composited-float-under-composited-inline-individual-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/composited-float-under-composited-inline-individual-expected.txt
index 353e6353..98bb542 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/composited-float-under-composited-inline-individual-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/composited-float-under-composited-inline-individual-expected.txt
@@ -13,7 +13,7 @@
     },
     {
       "name": "LayoutBlockFlow (relative positioned) (floating) DIV id='float'",
-      "position": [-50, -50],
+      "position": [58, 58],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "drawsContent": true,
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/containing-block-added-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/containing-block-added-expected.txt
index df25721..401376bc 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/containing-block-added-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/containing-block-added-expected.txt
@@ -16,7 +16,6 @@
     {
       "name": "LayoutBlockFlow (positioned) DIV id='container'",
       "position": [200, 100],
-      "transformOrigin": [50, 50],
       "bounds": [125, 125],
       "drawsContent": true,
       "backgroundColor": "#0000FF",
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/containing-block-added-individual-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/containing-block-added-individual-expected.txt
index df25721..401376bc 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/containing-block-added-individual-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/containing-block-added-individual-expected.txt
@@ -16,7 +16,6 @@
     {
       "name": "LayoutBlockFlow (positioned) DIV id='container'",
       "position": [200, 100],
-      "transformOrigin": [50, 50],
       "bounds": [125, 125],
       "drawsContent": true,
       "backgroundColor": "#0000FF",
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/fixed-pos-inside-composited-intermediate-layer-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/fixed-pos-inside-composited-intermediate-layer-expected.txt
index 3622f9ae..047786a6 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/fixed-pos-inside-composited-intermediate-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/fixed-pos-inside-composited-intermediate-layer-expected.txt
@@ -7,8 +7,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow DIV class='compositedBehind'",
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/invalidate-when-leaving-squashed-layer-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/invalidate-when-leaving-squashed-layer-expected.txt
index 9fe1ead..831e032 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/invalidate-when-leaving-squashed-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/invalidate-when-leaving-squashed-layer-expected.txt
@@ -7,8 +7,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV",
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/invalidation-for-subpixel-offset-of-squashed-layer-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/invalidation-for-subpixel-offset-of-squashed-layer-expected.txt
index 92f3c59..ffc0682 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/invalidation-for-subpixel-offset-of-squashed-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/invalidation-for-subpixel-offset-of-squashed-layer-expected.txt
@@ -7,8 +7,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV",
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/invalidations-on-composited-layers-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/invalidations-on-composited-layers-expected.txt
index bdac45f5..8dea172 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/invalidations-on-composited-layers-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/invalidations-on-composited-layers-expected.txt
@@ -23,7 +23,7 @@
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='child'",
-      "position": [50, 50],
+      "position": [58, 58],
       "bounds": [75, 75],
       "contentsOpaque": true,
       "drawsContent": true,
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/new-stacking-context-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/new-stacking-context-expected.txt
index c499330..c337c12 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/new-stacking-context-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/new-stacking-context-expected.txt
@@ -10,16 +10,16 @@
       "name": "LayoutBlockFlow DIV",
       "position": [8, 8],
       "bounds": [100, 100],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [100, 100],
-      "shouldFlattenTransform": false
+      "position": [8, 8],
+      "bounds": [100, 100]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 8],
       "bounds": [200, 200],
       "drawsContent": true,
       "paintInvalidations": [
@@ -32,17 +32,18 @@
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 8],
       "bounds": [100, 100]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [0, 100],
+      "position": [8, 108],
       "bounds": [100, 0],
       "drawsContent": true
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [100, 0],
+      "position": [108, 8],
       "bounds": [0, 100],
       "drawsContent": true
     },
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/overlap-test-with-filter-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/overlap-test-with-filter-expected.txt
index 3d45fbe..058961c 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/overlap-test-with-filter-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/overlap-test-with-filter-expected.txt
@@ -45,6 +45,12 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#D3D3D3",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/repaint-overflow-scrolled-squashed-content-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/repaint-overflow-scrolled-squashed-content-expected.txt
index b1529ef3..1c4b6f6 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/repaint-overflow-scrolled-squashed-content-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/repaint-overflow-scrolled-squashed-content-expected.txt
@@ -9,11 +9,11 @@
     {
       "name": "Ancestor Clipping Layer",
       "position": [8, 8],
-      "bounds": [185, 185],
-      "shouldFlattenTransform": false
+      "bounds": [185, 185]
     },
     {
       "name": "LayoutBlockFlow DIV id='foo2'",
+      "position": [8, 8],
       "bounds": [150, 1000],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -21,6 +21,7 @@
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (positioned) DIV id='foo')",
+      "position": [8, 8],
       "bounds": [100, 1000],
       "drawsContent": true,
       "paintInvalidations": [
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/repaint-squashed-layer-in-rect-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/repaint-squashed-layer-in-rect-expected.txt
index aee98794..7ebfdf18 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/repaint-squashed-layer-in-rect-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/repaint-squashed-layer-in-rect-expected.txt
@@ -7,8 +7,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow DIV",
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/repaint-via-layout-offset-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/repaint-via-layout-offset-expected.txt
index 8806f9b..d26cff6 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/repaint-via-layout-offset-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/repaint-via-layout-offset-expected.txt
@@ -7,8 +7,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow DIV",
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/resize-squashing-layer-that-needs-full-repaint-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/resize-squashing-layer-that-needs-full-repaint-expected.txt
index dc0c3be..e0ba001 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/resize-squashing-layer-that-needs-full-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/resize-squashing-layer-that-needs-full-repaint-expected.txt
@@ -7,8 +7,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow DIV",
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/scrolling-without-painting-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/scrolling-without-painting-expected.txt
index 38dc575..e309e33 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/scrolling-without-painting-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/scrolling-without-painting-expected.txt
@@ -10,32 +10,32 @@
       "name": "LayoutBlockFlow DIV id='scroller'",
       "position": [8, 8],
       "bounds": [202, 202],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "position": [1, 1],
-      "bounds": [185, 185],
-      "shouldFlattenTransform": false
+      "position": [9, 9],
+      "bounds": [185, 185]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [9, 9],
       "bounds": [185, 1025],
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 8],
       "bounds": [202, 202]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [1, 186],
+      "position": [9, 194],
       "bounds": [185, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [186, 1],
+      "position": [194, 9],
       "bounds": [15, 185],
       "paintInvalidations": [
         {
@@ -47,7 +47,7 @@
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [186, 186],
+      "position": [194, 194],
       "bounds": [15, 15],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/should-not-clip-composited-overflow-scrolling-layer-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/should-not-clip-composited-overflow-scrolling-layer-expected.txt
index c8f069b..76f2957 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/should-not-clip-composited-overflow-scrolling-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/should-not-clip-composited-overflow-scrolling-layer-expected.txt
@@ -10,16 +10,16 @@
       "name": "LayoutBlockFlow DIV id='container'",
       "position": [8, 8],
       "bounds": [400, 300],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [385, 285],
-      "shouldFlattenTransform": false
+      "position": [8, 8],
+      "bounds": [385, 285]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 8],
       "bounds": [1000, 1000],
       "drawsContent": true,
       "paintInvalidations": [
@@ -32,11 +32,12 @@
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 8],
       "bounds": [400, 300]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [0, 285],
+      "position": [8, 293],
       "bounds": [385, 15],
       "paintInvalidations": [
         {
@@ -48,7 +49,7 @@
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [385, 0],
+      "position": [393, 8],
       "bounds": [15, 285],
       "paintInvalidations": [
         {
@@ -60,7 +61,7 @@
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [385, 285],
+      "position": [393, 293],
       "bounds": [15, 15],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/should-not-repaint-composited-descendants-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/should-not-repaint-composited-descendants-expected.txt
index ce5ebd7a..1f4d56c 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/should-not-repaint-composited-descendants-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/should-not-repaint-composited-descendants-expected.txt
@@ -34,11 +34,12 @@
     },
     {
       "name": "Child Containment Layer",
+      "position": [38, 38],
       "bounds": [90, 90]
     },
     {
       "name": "LayoutBlockFlow DIV class='composited child'",
-      "position": [-30, 20],
+      "position": [8, 58],
       "bounds": [50, 50],
       "contentsOpaque": true,
       "drawsContent": true,
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/should-not-repaint-composited-descendants-on-overflow-change-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/should-not-repaint-composited-descendants-on-overflow-change-expected.txt
index 4d655e6..b902ad0 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/should-not-repaint-composited-descendants-on-overflow-change-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/should-not-repaint-composited-descendants-on-overflow-change-expected.txt
@@ -29,11 +29,11 @@
     {
       "name": "Ancestor Clipping Layer",
       "position": [0, 200],
-      "bounds": [200, 200],
-      "shouldFlattenTransform": false
+      "bounds": [200, 200]
     },
     {
       "name": "LayoutBlockFlow DIV class='composited-child'",
+      "position": [0, 200],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -52,12 +52,11 @@
     {
       "name": "Ancestor Clipping Layer",
       "position": [0, 200],
-      "bounds": [200, 200],
-      "shouldFlattenTransform": false
+      "bounds": [200, 200]
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='composited-child overflow-child'",
-      "position": [150, 150],
+      "position": [150, 350],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "drawsContent": true,
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/should-not-repaint-composited-transform-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/should-not-repaint-composited-transform-expected.txt
index b0b76a7e..e9ba4317 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/should-not-repaint-composited-transform-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/should-not-repaint-composited-transform-expected.txt
@@ -11,6 +11,12 @@
       "position": [8, 8],
       "bounds": [102, 102],
       "drawsContent": true,
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/should-not-repaint-scrolling-contents-outline-change-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/should-not-repaint-scrolling-contents-outline-change-expected.txt
index 3538305..0b4e80b 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/should-not-repaint-scrolling-contents-outline-change-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/should-not-repaint-scrolling-contents-outline-change-expected.txt
@@ -10,7 +10,6 @@
       "name": "LayoutBlockFlow DIV id='target'",
       "position": [-2, -2],
       "bounds": [220, 220],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#0000FF",
       "paintInvalidations": [
@@ -23,34 +22,34 @@
     },
     {
       "name": "Scrolling Layer",
-      "position": [10, 10],
-      "bounds": [185, 185],
-      "shouldFlattenTransform": false
+      "position": [8, 8],
+      "bounds": [185, 185]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 8],
       "bounds": [185, 2000],
       "contentsOpaque": true,
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
-      "position": [10, 10],
+      "position": [8, 8],
       "bounds": [200, 200]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [0, 185],
+      "position": [8, 193],
       "bounds": [185, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [185, 0],
+      "position": [193, 8],
       "bounds": [15, 185]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [185, 185],
+      "position": [193, 193],
       "bounds": [15, 15],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/squash-partial-repaint-inside-squashed-layer-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/squash-partial-repaint-inside-squashed-layer-expected.txt
index 2bd77a3..d8225cb 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/squash-partial-repaint-inside-squashed-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/squash-partial-repaint-inside-squashed-layer-expected.txt
@@ -7,8 +7,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited box behind'",
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/squashing-inside-preserve-3d-element-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/squashing-inside-preserve-3d-element-expected.txt
index 916bd7b..b7afb30 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/squashing-inside-preserve-3d-element-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/squashing-inside-preserve-3d-element-expected.txt
@@ -7,23 +7,21 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow DIV",
       "position": [8, 8],
       "bounds": [100, 100],
       "contentsOpaque": true,
-      "3dRenderingContext": 1,
       "drawsContent": true,
-      "backgroundColor": "#D3D3D3"
+      "backgroundColor": "#D3D3D3",
+      "transform": 1
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (positioned) DIV id='target')",
       "position": [28, 28],
       "bounds": [100, 100],
-      "3dRenderingContext": 1,
       "drawsContent": true,
       "paintInvalidations": [
         {
@@ -31,7 +29,18 @@
           "rect": [0, 0, 100, 100],
           "reason": "style change"
         }
-      ]
+      ],
+      "transform": 2
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "renderingContext": 1
+    },
+    {
+      "id": 2,
+      "renderingContext": 1
     }
   ],
   "objectPaintInvalidations": [
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/tricky-element-removal-crash-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/tricky-element-removal-crash-expected.txt
index e271029e..095c34f 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/tricky-element-removal-crash-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/tricky-element-removal-crash-expected.txt
@@ -7,8 +7,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow DIV",
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/updating-scrolling-content-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/updating-scrolling-content-expected.txt
index 8687f2f..4d0d152 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/updating-scrolling-content-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/updating-scrolling-content-expected.txt
@@ -10,16 +10,16 @@
       "name": "LayoutBlockFlow DIV id='scroller'",
       "position": [8, 8],
       "bounds": [200, 200],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [185, 185],
-      "shouldFlattenTransform": false
+      "position": [8, 8],
+      "bounds": [185, 185]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 8],
       "bounds": [185, 1200],
       "drawsContent": true,
       "paintInvalidations": [
@@ -32,16 +32,17 @@
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 8],
       "bounds": [200, 200]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [0, 185],
+      "position": [8, 193],
       "bounds": [185, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [185, 0],
+      "position": [193, 8],
       "bounds": [15, 185],
       "paintInvalidations": [
         {
@@ -53,7 +54,7 @@
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [185, 185],
+      "position": [193, 193],
       "bounds": [15, 15],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/filter-repaint-accelerated-child-with-filter-child-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/filter-repaint-accelerated-child-with-filter-child-expected.txt
index 32d74f3..9635e55 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/filter-repaint-accelerated-child-with-filter-child-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/filter-repaint-accelerated-child-with-filter-child-expected.txt
@@ -14,8 +14,7 @@
     },
     {
       "name": "LayoutBlockFlow DIV class='accelerated'",
-      "position": [-12, -12],
-      "transformOrigin": [112, 112],
+      "position": [-4, -4],
       "bounds": [212, 257],
       "drawsContent": true,
       "paintInvalidations": [
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/filter-repaint-accelerated-on-accelerated-filter-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/filter-repaint-accelerated-on-accelerated-filter-expected.txt
index 4036442..8664e0d3 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/filter-repaint-accelerated-on-accelerated-filter-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/filter-repaint-accelerated-on-accelerated-filter-expected.txt
@@ -14,6 +14,7 @@
     },
     {
       "name": "LayoutBlockFlow DIV id='resize' class='drop-shadow accelerated'",
+      "position": [8, 8],
       "bounds": [100, 200],
       "contentsOpaque": true,
       "drawsContent": true,
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/filter-repaint-on-accelerated-layer-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/filter-repaint-on-accelerated-layer-expected.txt
index cfb56ac..4e1ce644 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/filter-repaint-on-accelerated-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/filter-repaint-on-accelerated-layer-expected.txt
@@ -14,6 +14,7 @@
     },
     {
       "name": "LayoutBlockFlow DIV id='resize' class='accelerated'",
+      "position": [8, 8],
       "bounds": [100, 200],
       "contentsOpaque": true,
       "drawsContent": true,
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/flipped-blocks-writing-mode-scroll-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/flipped-blocks-writing-mode-scroll-expected.txt
index 41e30e957..00984ec3 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/flipped-blocks-writing-mode-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/flipped-blocks-writing-mode-scroll-expected.txt
@@ -10,16 +10,16 @@
       "name": "LayoutBlockFlow DIV id='scroller'",
       "position": [8, 8],
       "bounds": [400, 400],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [400, 385],
-      "shouldFlattenTransform": false
+      "position": [8, 8],
+      "bounds": [400, 385]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 8],
       "bounds": [10000, 385],
       "drawsContent": true,
       "paintInvalidations": [
@@ -32,11 +32,12 @@
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 8],
       "bounds": [400, 400]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [0, 385],
+      "position": [8, 393],
       "bounds": [400, 15],
       "paintInvalidations": [
         {
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-after-composited-scroll-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-after-composited-scroll-expected.txt
index 319ee1f..d6e42b2 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-after-composited-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-after-composited-scroll-expected.txt
@@ -10,16 +10,16 @@
       "name": "LayoutBlockFlow (positioned) DIV id='scroller'",
       "position": [300, 300],
       "bounds": [200, 200],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [185, 200],
-      "shouldFlattenTransform": false
+      "position": [300, 300],
+      "bounds": [185, 200]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [300, 300],
       "bounds": [185, 4900],
       "drawsContent": true,
       "paintInvalidations": [
@@ -32,11 +32,12 @@
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [300, 300],
       "bounds": [200, 200]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [185, 0],
+      "position": [485, 300],
       "bounds": [15, 200],
       "paintInvalidations": [
         {
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-cell-in-row-with-offset-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-cell-in-row-with-offset-expected.txt
index 8643054e..2da38c3 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-cell-in-row-with-offset-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-cell-in-row-with-offset-expected.txt
@@ -9,7 +9,6 @@
     {
       "name": "LayoutTableRow TR",
       "position": [8, 18],
-      "transformOrigin": [117, 0],
       "drawsContent": true,
       "backgroundColor": "#0000FF"
     },
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-descendants-when-receiving-paint-layer-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-descendants-when-receiving-paint-layer-expected.txt
index e803300..c3813f3c 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-descendants-when-receiving-paint-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-descendants-when-receiving-paint-layer-expected.txt
@@ -12,8 +12,7 @@
       "contentsOpaque": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV",
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-paint-in-iframe-in-composited-layer-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-paint-in-iframe-in-composited-layer-expected.txt
index 3c58224..36a2403 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-paint-in-iframe-in-composited-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-paint-in-iframe-in-composited-layer-expected.txt
@@ -9,7 +9,6 @@
     {
       "name": "LayoutBlockFlow DIV",
       "position": [8, 408],
-      "transformOrigin": [100, 100],
       "bounds": [304, 200],
       "drawsContent": true,
       "paintInvalidations": [
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/invalidation-on-foreground-graphics-layer-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/invalidation-on-foreground-graphics-layer-expected.txt
index 179f15b5..b655979f 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/invalidation-on-foreground-graphics-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/invalidation-on-foreground-graphics-layer-expected.txt
@@ -11,17 +11,17 @@
       "position": [8, 8],
       "bounds": [200, 200],
       "contentsOpaque": true,
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#D3D3D3"
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [185, 185],
-      "shouldFlattenTransform": false
+      "position": [8, 8],
+      "bounds": [185, 185]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 8],
       "bounds": [300, 300],
       "drawsContent": true,
       "paintInvalidations": [
@@ -34,6 +34,7 @@
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV",
+      "position": [8, 8],
       "bounds": [200, 200],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -41,6 +42,7 @@
     },
     {
       "name": "LayoutBlockFlow DIV (foreground) Layer",
+      "position": [8, 8],
       "bounds": [300, 300],
       "drawsContent": true,
       "paintInvalidations": [
@@ -53,21 +55,22 @@
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 8],
       "bounds": [200, 200]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [0, 185],
+      "position": [8, 193],
       "bounds": [185, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [185, 0],
+      "position": [193, 8],
       "bounds": [15, 185]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [185, 185],
+      "position": [193, 193],
       "bounds": [15, 15],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/multiple-backgrounds-style-change-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/multiple-backgrounds-style-change-expected.txt
index 11a35a1..d40273e 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/multiple-backgrounds-style-change-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/multiple-backgrounds-style-change-expected.txt
@@ -11,6 +11,12 @@
       "position": [8, 8],
       "bounds": [202, 202],
       "drawsContent": true,
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/overflow-changed-on-child-of-composited-layer-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/overflow-changed-on-child-of-composited-layer-expected.txt
index ab33c1ac..9d78be1 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/overflow-changed-on-child-of-composited-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/overflow-changed-on-child-of-composited-layer-expected.txt
@@ -9,7 +9,6 @@
     {
       "name": "LayoutBlockFlow DIV id='parent'",
       "position": [27, 19],
-      "transformOrigin": [373, 51],
       "bounds": [745, 102],
       "drawsContent": true,
       "paintInvalidations": [
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/overflow-move-after-scroll-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/overflow-move-after-scroll-expected.txt
index b71c65d..41f2cc3 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/overflow-move-after-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/overflow-move-after-scroll-expected.txt
@@ -10,16 +10,16 @@
       "name": "LayoutBlockFlow (positioned) DIV id='scroller' class='scroller'",
       "position": [10, 60],
       "bounds": [700, 400],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [685, 385],
-      "shouldFlattenTransform": false
+      "position": [10, 60],
+      "bounds": [685, 385]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [10, 60],
       "bounds": [685, 600],
       "drawsContent": true,
       "paintInvalidations": [
@@ -37,16 +37,17 @@
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [10, 60],
       "bounds": [700, 400]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [0, 385],
+      "position": [10, 445],
       "bounds": [685, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [685, 0],
+      "position": [695, 60],
       "bounds": [15, 385],
       "paintInvalidations": [
         {
@@ -58,7 +59,7 @@
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [685, 385],
+      "position": [695, 445],
       "bounds": [15, 15],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/overflow-scroll-after-move-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/overflow-scroll-after-move-expected.txt
index 22bec808..8ca3be8 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/overflow-scroll-after-move-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/overflow-scroll-after-move-expected.txt
@@ -10,16 +10,16 @@
       "name": "LayoutBlockFlow (positioned) DIV id='scroller'",
       "position": [10, 60],
       "bounds": [300, 400],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [285, 385],
-      "shouldFlattenTransform": false
+      "position": [10, 60],
+      "bounds": [285, 385]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [10, 60],
       "bounds": [285, 900],
       "drawsContent": true,
       "paintInvalidations": [
@@ -37,16 +37,17 @@
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [10, 60],
       "bounds": [300, 400]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [0, 385],
+      "position": [10, 445],
       "bounds": [285, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [285, 0],
+      "position": [295, 60],
       "bounds": [15, 385],
       "paintInvalidations": [
         {
@@ -58,7 +59,7 @@
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [285, 385],
+      "position": [295, 445],
       "bounds": [15, 15],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/overflow-scroll-composited-non-stacking-child-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/overflow-scroll-composited-non-stacking-child-expected.txt
index 82a406b0..9b83239 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/overflow-scroll-composited-non-stacking-child-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/overflow-scroll-composited-non-stacking-child-expected.txt
@@ -39,17 +39,16 @@
     {
       "name": "Ancestor Clipping Layer",
       "position": [23, 65],
-      "bounds": [285, 175],
-      "shouldFlattenTransform": false
+      "bounds": [285, 175]
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='list'",
-      "position": [20, -30],
+      "position": [43, 35],
       "bounds": [180, 250]
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (relative positioned) DIV class='commit')",
-      "position": [20, -30],
+      "position": [43, 35],
       "bounds": [180, 250],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/repaint-composited-child-in-scrolled-container-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/repaint-composited-child-in-scrolled-container-expected.txt
index 898dd982..ab291cf 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/repaint-composited-child-in-scrolled-container-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/repaint-composited-child-in-scrolled-container-expected.txt
@@ -16,12 +16,11 @@
     {
       "name": "Ancestor Clipping Layer",
       "position": [8, 8],
-      "bounds": [285, 285],
-      "shouldFlattenTransform": false
+      "bounds": [285, 285]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='container'",
-      "position": [-315, 0],
+      "position": [-307, 8],
       "bounds": [600, 600],
       "contentsOpaque": true,
       "drawsContent": true,
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/svg/animated-svg-as-image-transformed-offscreen-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/svg/animated-svg-as-image-transformed-offscreen-expected.txt
index 3ce4dc4..8d493bb 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/svg/animated-svg-as-image-transformed-offscreen-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/svg/animated-svg-as-image-transformed-offscreen-expected.txt
@@ -11,6 +11,12 @@
       "position": [8, 8],
       "bounds": [2000, 2000],
       "drawsContent": true,
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/text-emphasis-h.html b/third_party/WebKit/LayoutTests/paint/invalidation/text-emphasis-h.html
index aff7e3f..f6ae277 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/text-emphasis-h.html
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/text-emphasis-h.html
@@ -10,14 +10,14 @@
     <div style="-webkit-text-emphasis: 'm';">
         1111
     </div>
-    <div style="-webkit-text-emphasis: 'm'; -webkit-text-emphasis-position: under;">
+    <div style="-webkit-text-emphasis: 'm'; -webkit-text-emphasis-position: under left;">
         1111
     </div>
 
     <div style="-webkit-writing-mode: vertical-rl; -webkit-text-emphasis: 'm';">
         1111
     </div>
-    <div style="-webkit-writing-mode: vertical-rl; -webkit-text-emphasis: 'm'; -webkit-text-emphasis-position: under;">
+    <div style="-webkit-writing-mode: vertical-rl; -webkit-text-emphasis: 'm'; -webkit-text-emphasis-position: under left;">
         1111
     </div>
 </div>
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/text-emphasis-v.html b/third_party/WebKit/LayoutTests/paint/invalidation/text-emphasis-v.html
index 1b43ad1a..9bc7cf988 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/text-emphasis-v.html
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/text-emphasis-v.html
@@ -18,14 +18,14 @@
     <div style="-webkit-text-emphasis: 'm';">
         1111
     </div>
-    <div style="-webkit-text-emphasis: 'm'; -webkit-text-emphasis-position: under;">
+    <div style="-webkit-text-emphasis: 'm'; -webkit-text-emphasis-position: under left;">
         1111
     </div>
 
     <div style="-webkit-text-emphasis: 'm';">
         1111
     </div>
-    <div style="-webkit-text-emphasis: 'm'; -webkit-text-emphasis-position: under;">
+    <div style="-webkit-text-emphasis: 'm'; -webkit-text-emphasis-position: under left;">
         1111
     </div>
 </div>
diff --git a/third_party/WebKit/LayoutTests/paint/markers/suggestion-marker-basic.html b/third_party/WebKit/LayoutTests/paint/markers/suggestion-marker-basic.html
new file mode 100644
index 0000000..46215bd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/paint/markers/suggestion-marker-basic.html
@@ -0,0 +1,131 @@
+<!doctype html>
+<script src="../../resources/run-after-layout-and-paint.js"></script>
+<!-- Tests various permutations of active suggestion underlines in LTR and RTL
+     text. -->
+<div dir="rtl" style="float: right;">
+    <p>RTL</p>
+    <div contenteditable id="markRtlAll" dir="rtl">markRtlAll</div>
+    <div contenteditable id="markRtlAllThick">markRtlAllThick</div>
+    <div contenteditable id="markRtlBeginning">markRtlBeginning</div>
+    <div contenteditable id="markRtlAllExceptFirstAndLast">markRtlAllExceptFirstAndLast</div>
+    <div contenteditable id="markRtlEnd">markRtlEnd</div>
+    <div contenteditable id="markRtlAcrossNodes"><div>mark<span>Rtl</span></div><div>AcrossNodes</div></div>
+</div>
+
+<div style="float: left;">
+    <p>LTR</p>
+    <div contenteditable id="markAll">markAll</div>
+    <div contenteditable id="markAllThick">markAllThick</div>
+    <div contenteditable id="markAllDifferentColors">markAllDifferentColors</div>
+    <div contenteditable id="markBeginning">markBeginning</div>
+    <div contenteditable id="markAllExceptFirstAndLast">markAllExceptFirstAndLast</div>
+    <div contenteditable id="markEnd">markEnd</div>
+    <div contenteditable id="markNothingZero">markNothingZero</div>
+    <div contenteditable id="markNothingEnd">markNothingEnd</div>
+    <div contenteditable id="markAcrossNodes"><div>mark<span>Across</span></div><div>Nodes</div></div>
+    <div contenteditable id="overridingSpellingMarkerAtBeginning">overridingSpellingMarkerAtBeginning</div>
+    <div contenteditable id="overridingSpellingMarkerAtEnd">overridingSpellingMarkerAtEnd</div>
+    <div contenteditable id="overridingSpellingMarkerIntersectingBeginning">overridingSpellingMarkerIntersectingBeginning</div>
+    <div contenteditable id="overridingSpellingMarkerIntersectingEnd">overridingSpellingMarkerIntersectingEnd</div>
+    <div contenteditable id="notOverridingSpellingMarkersTouching">notOverridingSpellingMarkersTouching</div>
+    <div contenteditable id="overridingCompositionMarkerAtBeginning">overridingCompositionMarkerAtBeginning</div>
+    <div contenteditable id="overridingCompositionMarkerAtEnd">overridingCompositionMarkerAtEnd</div>
+    <div contenteditable id="overridingCompositionMarkerIntersectingBeginning">overridingCompositionMarkerIntersectingBeginning</div>
+    <div contenteditable id="overridingCompositionMarkerIntersectingEnd">overridingCompositionMarkerIntersectingEnd</div>
+    <div contenteditable id="notOverridingCompositionMarkersTouching">notOverridingCompositionMarkersTouching</div>
+</div>
+
+<script>
+function addSuggestionMarker(elem, start, end, underlineColor, thick, backgroundColor) {
+    var range = document.createRange();
+    var textNode = elem.firstChild;
+    range.setStart(textNode, start);
+    range.setEnd(textNode, end);
+    if (typeof internals !== 'undefined')
+        internals.addSuggestionMarker(range, [], 'white', underlineColor, thick, backgroundColor);
+};
+
+function addCompositionMarker(elem, start, end, underlineColor, thick, backgroundColor) {
+    var range = document.createRange();
+    var textNode = elem.firstChild;
+    range.setStart(textNode, start);
+    range.setEnd(textNode, end);
+    if (typeof internals !== 'undefined')
+        internals.addCompositionMarker(range, underlineColor, thick, backgroundColor);
+};
+
+function addSpellingMarker(elem, start, end) {
+    var range = document.createRange();
+    var textNode = elem.firstChild;
+    range.setStart(textNode, start);
+    range.setEnd(textNode, end);
+    if (typeof internals !== 'undefined')
+        internals.setMarker(document, range, 'spelling');
+}
+
+function addSuggestionMarkerSimple(elem, start, end) {
+    addSuggestionMarker(elem, start, end, 'orange', 'thin', 'lightBlue');
+};
+
+function highlightAcrossNodes(startNode, start, endNode, end) {
+    var range = document.createRange();
+    range.setStart(startNode, start);
+    range.setEnd(endNode, end);
+    if (typeof internals !== 'undefined')
+        internals.addSuggestionMarker(range, [], 'white', 'orange', 'thin', 'lightBlue');
+};
+
+onload = runAfterLayoutAndPaint(function() {
+    addSuggestionMarkerSimple(markAll, 0, 7);
+    addSuggestionMarker(markAllThick, 0, 12, 'orange', 'thick', 'lightBlue');
+    addSuggestionMarker(markAllDifferentColors, 0, 21, 'purple', 'thick', 'lightYellow');
+    addSuggestionMarkerSimple(markBeginning, 0, 3);
+    addSuggestionMarkerSimple(markAllExceptFirstAndLast, 1, 24);
+    addSuggestionMarkerSimple(markEnd, 4, 7);
+    addSuggestionMarkerSimple(markNothingZero, 0, 0);
+    addSuggestionMarkerSimple(markNothingEnd, 6, 6);
+
+    addSuggestionMarkerSimple(markRtlAll, 0, 10);
+    addSuggestionMarker(markRtlAllThick, 0, 15, 'orange', 'thick', 'lightBlue');
+    addSuggestionMarkerSimple(markRtlBeginning, 0, 3);
+    addSuggestionMarkerSimple(markRtlAllExceptFirstAndLast, 1, 27);
+    addSuggestionMarkerSimple(markRtlEnd, 7, 10);
+
+    highlightAcrossNodes(markAcrossNodes.childNodes[0].firstChild, 3,
+        markAcrossNodes.childNodes[1].firstChild, 3);
+    highlightAcrossNodes(markRtlAcrossNodes.childNodes[0].firstChild, 3,
+    markRtlAcrossNodes.childNodes[1].firstChild, 3);
+
+    addSuggestionMarkerSimple(overridingSpellingMarkerAtBeginning, 0, 6);
+    addSpellingMarker(overridingSpellingMarkerAtBeginning, 0, 1);
+
+    addSuggestionMarkerSimple(overridingSpellingMarkerAtEnd, 0, 6);
+    addSpellingMarker(overridingSpellingMarkerAtEnd, 5, 6);
+
+    addSuggestionMarkerSimple(overridingSpellingMarkerIntersectingBeginning, 1, 5);
+    addSpellingMarker(overridingSpellingMarkerIntersectingBeginning, 0, 2);
+
+    addSuggestionMarkerSimple(overridingSpellingMarkerIntersectingEnd, 1, 5);
+    addSpellingMarker(overridingSpellingMarkerIntersectingEnd, 4, 6);
+
+    addSuggestionMarkerSimple(notOverridingSpellingMarkersTouching, 1, 5);
+    addSpellingMarker(notOverridingSpellingMarkersTouching, 0, 1);
+    addSpellingMarker(notOverridingSpellingMarkersTouching, 5, 6);
+
+    addSuggestionMarkerSimple(overridingCompositionMarkerAtBeginning, 0, 6);
+    addCompositionMarker(overridingCompositionMarkerAtBeginning, 0, 1, 'purple', 'thick', 'lightYellow');
+
+    addSuggestionMarkerSimple(overridingCompositionMarkerAtEnd, 0, 6);
+    addCompositionMarker(overridingCompositionMarkerAtEnd, 5, 6, 'purple', 'thick', 'lightYellow');
+
+    addSuggestionMarkerSimple(overridingCompositionMarkerIntersectingBeginning, 1, 5);
+    addCompositionMarker(overridingCompositionMarkerIntersectingBeginning, 0, 2, 'purple', 'thick', 'lightYellow');
+
+    addSuggestionMarkerSimple(overridingCompositionMarkerIntersectingEnd, 1, 5);
+    addCompositionMarker(overridingCompositionMarkerIntersectingEnd, 4, 6, 'purple', 'thick', 'lightYellow');
+
+    addSuggestionMarkerSimple(notOverridingCompositionMarkersTouching, 1, 5);
+    addCompositionMarker(notOverridingCompositionMarkersTouching, 0, 1, 'purple', 'thick', 'lightYellow');
+    addCompositionMarker(notOverridingCompositionMarkersTouching, 5, 6, 'purple', 'thick', 'lightYellow');
+}, true);
+</script>
diff --git a/third_party/WebKit/LayoutTests/paint/markers/suggestion-marker-split.html b/third_party/WebKit/LayoutTests/paint/markers/suggestion-marker-split.html
new file mode 100644
index 0000000..a57e196
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/paint/markers/suggestion-marker-split.html
@@ -0,0 +1,36 @@
+<!doctype html>
+<script src="../../resources/run-after-layout-and-paint.js"></script>
+<!-- Text is injected after page load into the center of the initial text.
+  This results in an InlineTextBox with start() > 0, which allows testing
+  to make sure composition underlines are still painted in the right place. -->
+<div contenteditable id="markSplit">abc def</div>
+<div contenteditable id="markSplitTruncated" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis; width: 8em;">abcdefghi jklmnopqr</div>
+<script>
+function injectText(node, offset) {
+    var textNode = node.firstChild;
+    var replacementNode = textNode.splitText(offset);
+    var newTextNode = document.createTextNode(' xxx ');
+    node.insertBefore(newTextNode, replacementNode);
+}
+
+function highlightRange(node) {
+    var range = document.createRange();
+    var textNode = node.childNodes[2];
+    range.setStart(textNode, 0);
+    range.setEnd(textNode, 4);
+    if (typeof internals !== 'undefined')
+        internals.addSuggestionMarker(range, [], 'white', 'orange', 'thin', 'lightBlue');
+}
+
+onload = runAfterLayoutAndPaint(function() {
+    injectText(markSplit, 3);
+    // TODO(wkorman): This ITB has start=1, end=3, truncation=USHRT_MAX, len=3.
+    // Validate that the actual painting behavior is what's expected.
+    highlightRange(markSplit);
+
+    injectText(markSplitTruncated, 9);
+    // TODO(wkorman): This ITB has start=1, end=9, truncation=3, len=9. Validate
+    // that the actual painting behavior is what's expected.
+    highlightRange(markSplitTruncated);
+}, true);
+</script>
diff --git a/third_party/WebKit/LayoutTests/platform/android/harness-tests/wpt/console_logging-expected.txt b/third_party/WebKit/LayoutTests/platform/android/harness-tests/wpt/console_logging-expected.txt
index 45db978..7dbc1aa6 100644
--- a/third_party/WebKit/LayoutTests/platform/android/harness-tests/wpt/console_logging-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/android/harness-tests/wpt/console_logging-expected.txt
@@ -1,4 +1,4 @@
 This is a testharness.js-based test.
-FAIL Test needs to fail so that an expected.txt file is written out and be examined for console messages.assert_true: expected true got false
+FAIL Test needs to fail so that an expected.txt file is written out and be examined for console messages. assert_true: expected true got false
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/bounds-ignores-hidden-composited-descendant-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/bounds-ignores-hidden-composited-descendant-expected.txt
deleted file mode 100644
index 3810e8c..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/bounds-ignores-hidden-composited-descendant-expected.txt
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true
-    },
-    {
-      "name": "LayoutBlockFlow (positioned) DIV class='composited'",
-      "position": [10, 10],
-      "transformOrigin": [-10, -10],
-      "bounds": [590, 210],
-      "drawsContent": true
-    },
-    {
-      "name": "LayoutBlockFlow (positioned) DIV class='composited'",
-      "position": [10, 260],
-      "transformOrigin": [-10, -10],
-      "bounds": [590, 210],
-      "drawsContent": true
-    },
-    {
-      "name": "LayoutBlockFlow (relative positioned) DIV class='composited inner box'",
-      "position": [490, 110],
-      "bounds": [100, 100],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "backgroundColor": "#0000FF"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/composited-in-columns-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/composited-in-columns-expected.png
deleted file mode 100644
index 6f897b6..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/composited-in-columns-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/composited-in-columns-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/composited-in-columns-expected.txt
deleted file mode 100644
index d9d29ac3a..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/composited-in-columns-expected.txt
+++ /dev/null
@@ -1,41 +0,0 @@
- {
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true
-    },
-    {
-      "name": "LayoutBlockFlow DIV class='composited block'",
-      "position": [14, 164],
-      "bounds": [210, 60],
-      "drawsContent": true,
-      "backgroundColor": "#0000FF"
-    },
-    {
-      "name": "LayoutBlockFlow DIV class='composited box'",
-      "position": [5, 5],
-      "bounds": [50, 50],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "backgroundColor": "#008000"
-    },
-    {
-      "name": "LayoutBlockFlow DIV class='composited block'",
-      "position": [272, 89],
-      "bounds": [210, 60],
-      "drawsContent": true,
-      "backgroundColor": "#0000FF"
-    },
-    {
-      "name": "LayoutBlockFlow DIV class='composited box'",
-      "position": [5, 5],
-      "bounds": [50, 50],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "backgroundColor": "#008000"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/layer-due-to-layer-children-deep-switch-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/layer-due-to-layer-children-deep-switch-expected.txt
deleted file mode 100644
index a7451f1..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/layer-due-to-layer-children-deep-switch-expected.txt
+++ /dev/null
@@ -1,81 +0,0 @@
-This content is in the parent
-Box should switch between perspective and flat
-
-First dump layer tree:
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true
-    }
-  ]
-}
-
-Second dump layer tree:
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true
-    },
-    {
-      "name": "LayoutBlockFlow (relative positioned) DIV id='parent'",
-      "position": [8, 8],
-      "bounds": [342, 292],
-      "drawsContent": true
-    },
-    {
-      "name": "LayoutBlockFlow (relative positioned) DIV id='child'",
-      "position": [31, 41],
-      "bounds": [250, 220],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "backgroundColor": "#0000FF"
-    },
-    {
-      "name": "LayoutBlockFlow (relative positioned) DIV id='grandchild'",
-      "position": [10, 10],
-      "bounds": [200, 200],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "backgroundColor": "#FFFF00",
-      "transform": [
-        [0.866025403784439, 0.5, 0, 0],
-        [-0.5, 0.866025403784439, 0, 0],
-        [0, 0, 1, 0],
-        [0, 0, 0, 1]
-      ]
-    },
-    {
-      "name": "LayoutBlockFlow (relative positioned) DIV id='greatgrandchild'",
-      "position": [100, 0],
-      "bounds": [250, 100],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "backgroundColor": "#008000",
-      "transform": [
-        [0.5, 0, -0.866025403784439, 0.0021650635094611],
-        [0, 1, 0, 0],
-        [0.866025403784439, 0, 0.5, -0.00125],
-        [-30, 30, 100, 0.75]
-      ]
-    }
-  ]
-}
-
-Third dump layer tree:
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [785, 1382],
-      "contentsOpaque": true,
-      "drawsContent": true
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/layer-due-to-layer-children-switch-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/layer-due-to-layer-children-switch-expected.txt
deleted file mode 100644
index 8c8acee..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/layer-due-to-layer-children-switch-expected.txt
+++ /dev/null
@@ -1,59 +0,0 @@
-This content is in the parent
-Box should switch between perspective and flat
-
-First dump layer tree:
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true
-    }
-  ]
-}
-
-Second dump layer tree:
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true
-    },
-    {
-      "name": "LayoutBlockFlow (relative positioned) DIV id='parent' class='parent'",
-      "position": [8, 8],
-      "bounds": [242, 192],
-      "drawsContent": true
-    },
-    {
-      "name": "LayoutBlockFlow (relative positioned) DIV id='child' class='child'",
-      "position": [121, 41],
-      "bounds": [250, 100],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "backgroundColor": "#008000",
-      "transform": [
-        [0.707106781186548, 0, -0.707106781186548, 0.00117851130197758],
-        [0, 1, 0, 0],
-        [0.707106781186548, 0, 0.707106781186548, -0.00117851130197758],
-        [-50, 10, 100, 0.833333333333333]
-      ]
-    }
-  ]
-}
-
-Third dump layer tree:
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [785, 930],
-      "contentsOpaque": true,
-      "drawsContent": true
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/iframes/invisible-nested-iframe-show-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/compositing/iframes/invisible-nested-iframe-show-expected.txt
deleted file mode 100644
index f11cd18..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/iframes/invisible-nested-iframe-show-expected.txt
+++ /dev/null
@@ -1,94 +0,0 @@
-
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true
-    },
-    {
-      "name": "LayoutIFrame IFRAME",
-      "position": [-11, -11],
-      "bounds": [368, 218],
-      "drawsContent": true
-    },
-    {
-      "name": "Frame Overflow Controls Host Layer",
-      "position": [34, 34],
-      "bounds": [300, 150]
-    },
-    {
-      "name": "Frame Clipping Layer",
-      "bounds": [285, 150]
-    },
-    {
-      "name": "Frame Scrolling Layer"
-    },
-    {
-      "name": "Content Root Layer",
-      "bounds": [285, 193]
-    },
-    {
-      "name": "LayoutView #document",
-      "bounds": [285, 193],
-      "drawsContent": true
-    },
-    {
-      "name": "LayoutIFrame IFRAME",
-      "position": [8, 8],
-      "bounds": [252, 172],
-      "drawsContent": true
-    },
-    {
-      "name": "Frame Overflow Controls Host Layer",
-      "position": [1, 1],
-      "bounds": [250, 170]
-    },
-    {
-      "name": "Frame Clipping Layer",
-      "bounds": [250, 170]
-    },
-    {
-      "name": "Frame Scrolling Layer"
-    },
-    {
-      "name": "Content Root Layer",
-      "bounds": [250, 230]
-    },
-    {
-      "name": "LayoutView #document",
-      "bounds": [250, 230],
-      "drawsContent": true,
-      "backgroundColor": "#C0C0C0"
-    },
-    {
-      "name": "LayoutBlockFlow DIV id='iframe-content' class='box'",
-      "position": [18, 10],
-      "bounds": [210, 210],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "backgroundColor": "#0000FF"
-    },
-    {
-      "name": "Frame Vertical Scrollbar Layer",
-      "position": [285, 0],
-      "bounds": [15, 150]
-    },
-    {
-      "name": "LayoutBlockFlow DIV class='box'",
-      "position": [18, 203],
-      "bounds": [210, 210],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "backgroundColor": "#0000FF",
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [0, 0, 1, 1]
-      ]
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/layer-creation/fixed-position-nonscrollable-body-mismatch-containers-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/compositing/layer-creation/fixed-position-nonscrollable-body-mismatch-containers-expected.txt
deleted file mode 100644
index ebc73b8..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/layer-creation/fixed-position-nonscrollable-body-mismatch-containers-expected.txt
+++ /dev/null
@@ -1,59 +0,0 @@
-Even though the fixed-position element's container is nonscrollable, it should still be composited because one of its ancestors is scrolling.
-
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true
-    },
-    {
-      "name": "LayoutBlockFlow DIV class='scrollable bigBox'",
-      "position": [8, 72],
-      "bounds": [302, 302],
-      "shouldFlattenTransform": false,
-      "drawsContent": true
-    },
-    {
-      "name": "Scrolling Layer",
-      "position": [1, 1],
-      "bounds": [285, 285],
-      "shouldFlattenTransform": false
-    },
-    {
-      "name": "Scrolling Contents Layer",
-      "bounds": [285, 800],
-      "drawsContent": true
-    },
-    {
-      "name": "Overflow Controls Host Layer",
-      "bounds": [302, 302]
-    },
-    {
-      "name": "Horizontal Scrollbar Layer",
-      "position": [1, 286],
-      "bounds": [285, 15]
-    },
-    {
-      "name": "Vertical Scrollbar Layer",
-      "position": [286, 1],
-      "bounds": [15, 285]
-    },
-    {
-      "name": "Scroll Corner Layer",
-      "position": [286, 286],
-      "bounds": [15, 15],
-      "drawsContent": true
-    },
-    {
-      "name": "LayoutBlockFlow (positioned) DIV class='fixed lime box'",
-      "position": [10, 100],
-      "bounds": [100, 100],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "backgroundColor": "#00FF00"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/layer-creation/no-compositing-for-preserve-3d-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/compositing/layer-creation/no-compositing-for-preserve-3d-expected.txt
deleted file mode 100644
index d7fca8d0..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/layer-creation/no-compositing-for-preserve-3d-expected.txt
+++ /dev/null
@@ -1,37 +0,0 @@
-This layer should not be composited.
-This layer should not be composited.
-This layer should be composited.
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [785, 618],
-      "contentsOpaque": true,
-      "drawsContent": true
-    },
-    {
-      "name": "LayoutBlockFlow DIV class='preserve3d'",
-      "position": [18, 394],
-      "bounds": [342, 182],
-      "shouldFlattenTransform": false,
-      "3dRenderingContext": 1,
-      "drawsContent": true
-    },
-    {
-      "name": "LayoutBlockFlow (relative positioned) DIV class='box'",
-      "position": [31, 51],
-      "bounds": [100, 100],
-      "contentsOpaque": true,
-      "3dRenderingContext": 1,
-      "drawsContent": true,
-      "backgroundColor": "#C0C0C0",
-      "transform": [
-        [0.984807753012208, 0, -0.17364817766693, 0],
-        [0, 1, 0, 0],
-        [0.17364817766693, 0, 0.984807753012208, 0],
-        [0, 0, 0, 1]
-      ]
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/overflow/textarea-scroll-touch-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/compositing/overflow/textarea-scroll-touch-expected.txt
deleted file mode 100644
index a505dce..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/overflow/textarea-scroll-touch-expected.txt
+++ /dev/null
@@ -1,82 +0,0 @@
-  
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true
-    },
-    {
-      "name": "LayoutTextControl TEXTAREA",
-      "position": [18, 18],
-      "bounds": [206, 126],
-      "shouldFlattenTransform": false,
-      "drawsContent": true,
-      "backgroundColor": "#CCCCCC"
-    },
-    {
-      "name": "Scrolling Layer",
-      "position": [1, 1],
-      "bounds": [189, 124],
-      "shouldFlattenTransform": false
-    },
-    {
-      "name": "Scrolling Contents Layer",
-      "bounds": [189, 328],
-      "contentsOpaque": true,
-      "drawsContent": true
-    },
-    {
-      "name": "Overflow Controls Host Layer",
-      "bounds": [206, 126]
-    },
-    {
-      "name": "Vertical Scrollbar Layer",
-      "position": [190, 1],
-      "bounds": [15, 109]
-    },
-    {
-      "name": "Scroll Corner Layer",
-      "position": [190, 110],
-      "bounds": [15, 15],
-      "drawsContent": true
-    },
-    {
-      "name": "LayoutTextControl TEXTAREA",
-      "position": [248, 18],
-      "bounds": [206, 126],
-      "shouldFlattenTransform": false,
-      "drawsContent": true,
-      "backgroundColor": "#CCCCCC"
-    },
-    {
-      "name": "Scrolling Layer",
-      "position": [1, 1],
-      "bounds": [189, 124],
-      "shouldFlattenTransform": false
-    },
-    {
-      "name": "Scrolling Contents Layer",
-      "bounds": [189, 328],
-      "contentsOpaque": true,
-      "drawsContent": true
-    },
-    {
-      "name": "Overflow Controls Host Layer",
-      "bounds": [206, 126]
-    },
-    {
-      "name": "Vertical Scrollbar Layer",
-      "position": [190, 1],
-      "bounds": [15, 109]
-    },
-    {
-      "name": "Scroll Corner Layer",
-      "position": [190, 110],
-      "bounds": [15, 15],
-      "drawsContent": true
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/rtl/rtl-iframe-absolute-overflow-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/rtl/rtl-iframe-absolute-overflow-expected.png
deleted file mode 100644
index d7547e6..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/rtl/rtl-iframe-absolute-overflow-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/rtl/rtl-iframe-fixed-overflow-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/rtl/rtl-iframe-fixed-overflow-expected.png
deleted file mode 100644
index 0ec8463..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/rtl/rtl-iframe-fixed-overflow-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/squashing/selection-repaint-with-gaps-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/compositing/squashing/selection-repaint-with-gaps-expected.txt
index c31a896..f071b9f 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/squashing/selection-repaint-with-gaps-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/squashing/selection-repaint-with-gaps-expected.txt
@@ -8,8 +8,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow DIV class='overlap'",
@@ -62,8 +61,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow DIV class='overlap'",
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/video/video-poster-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/compositing/video/video-poster-expected.txt
deleted file mode 100644
index e1dae87..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/video/video-poster-expected.txt
+++ /dev/null
@@ -1,64 +0,0 @@
-A <video> should not have a layer until playback begins.
-This test can not be run manually, it requires testRunner.layerTreeAsText.
-
-Case: No src, no poster
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true
-    }
-  ]
-}
-
-
-Case: Displaying poster
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [785, 605],
-      "contentsOpaque": true,
-      "drawsContent": true
-    }
-  ]
-}
-
-
-Case: Displaying movie
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [785, 813],
-      "contentsOpaque": true,
-      "drawsContent": true
-    },
-    {
-      "name": "LayoutVideo VIDEO",
-      "position": [8, 8],
-      "bounds": [352, 288]
-    },
-    {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
-    },
-    {
-      "name": "LayoutFlexibleBox (relative positioned) DIV",
-      "position": [8, 8],
-      "bounds": [352, 288],
-      "drawsContent": true
-    },
-    {
-      "name": "Squashing Layer (first squashed layer: LayoutFlexibleBox (relative positioned) DIV)",
-      "position": [8, 8],
-      "bounds": [352, 246],
-      "drawsContent": true
-    }
-  ]
-}
-
-
-
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/visibility/visibility-image-layers-dynamic-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/compositing/visibility/visibility-image-layers-dynamic-expected.txt
deleted file mode 100644
index a6f5968..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/visibility/visibility-image-layers-dynamic-expected.txt
+++ /dev/null
@@ -1,109 +0,0 @@
-
-
-
-Initial
-
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [785, 626],
-      "contentsOpaque": true,
-      "drawsContent": true
-    },
-    {
-      "name": "LayoutBlockFlow DIV class='composited container'",
-      "position": [18, 10],
-      "bounds": [749, 145]
-    },
-    {
-      "name": "LayoutBlockFlow DIV class='composited hidden container'",
-      "position": [14, 316],
-      "bounds": [757, 153],
-      "contentsVisible": false
-    },
-    {
-      "name": "LayoutImage IMG class='visible composited box'",
-      "position": [24, 24],
-      "bounds": [100, 100]
-    }
-  ]
-}
-After step 1
-
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [785, 1062],
-      "contentsOpaque": true,
-      "drawsContent": true
-    },
-    {
-      "name": "LayoutBlockFlow DIV class='composited container'",
-      "position": [18, 10],
-      "bounds": [749, 145]
-    },
-    {
-      "name": "LayoutImage IMG class='hidden composited box'",
-      "position": [20, 20],
-      "bounds": [100, 100]
-    },
-    {
-      "name": "LayoutBlockFlow DIV class='composited hidden container'",
-      "position": [14, 316],
-      "bounds": [757, 153],
-      "contentsVisible": false
-    },
-    {
-      "name": "LayoutImage IMG class='visible composited box'",
-      "position": [24, 24],
-      "bounds": [100, 100]
-    }
-  ]
-}
-After step 2
-
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [785, 1577],
-      "contentsOpaque": true,
-      "drawsContent": true
-    },
-    {
-      "name": "LayoutBlockFlow DIV class='composited container'",
-      "position": [18, 10],
-      "bounds": [749, 145]
-    },
-    {
-      "name": "LayoutImage IMG class='hidden composited box'",
-      "position": [20, 20],
-      "bounds": [100, 100]
-    },
-    {
-      "name": "LayoutBlockFlow DIV class='composited hidden container'",
-      "position": [14, 161],
-      "bounds": [757, 153],
-      "drawsContent": true
-    },
-    {
-      "name": "LayoutImage IMG class='composited box'",
-      "position": [24, 24],
-      "bounds": [100, 100]
-    },
-    {
-      "name": "LayoutBlockFlow DIV class='composited hidden container'",
-      "position": [14, 316],
-      "bounds": [757, 153],
-      "contentsVisible": false
-    },
-    {
-      "name": "LayoutImage IMG class='visible composited box'",
-      "position": [24, 24],
-      "bounds": [100, 100]
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/platform/linux/http/tests/devtools/console/console-format-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/http/tests/devtools/console/console-format-expected.txt
new file mode 100644
index 0000000..99da3d48
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/http/tests/devtools/console/console-format-expected.txt
@@ -0,0 +1,816 @@
+CONSOLE MESSAGE: line 27: test,test2,,,test4,,,,,
+CONSOLE MESSAGE: line 28: %o
+CONSOLE MESSAGE: line 29: %O
+CONSOLE MESSAGE: line 30: Test for zero "%f" in formatter
+CONSOLE MESSAGE: line 31: %% self-escape1
+CONSOLE MESSAGE: line 32: %%s self-escape2
+CONSOLE MESSAGE: line 33: %%ss self-escape3
+CONSOLE MESSAGE: line 34: %%s%s%%s self-escape4
+CONSOLE MESSAGE: line 35: %%%%% self-escape5
+CONSOLE MESSAGE: line 36: %%%s self-escape6
+CONSOLE MESSAGE: line 12: /^url\(\s*(?:(?:"(?:[^\\\"]|(?:\\[\da-f]{1,6}\s?|\.))*"|'(?:[^\\\']|(?:\\[\da-f]{1,6}\s?|\.))*')|(?:[!#$%&*-~\w]|(?:\\[\da-f]{1,6}\s?|\.))*)\s*\)/i
+CONSOLE MESSAGE: line 13: /^url\(\s*(?:(?:"(?:[^\\\"]|(?:\\[\da-f]{1,6}\s?|\.))*"|'(?:[^\\\']|(?:\\[\da-f]{1,6}\s?|\.))*')|(?:[!#$%&*-~\w]|(?:\\[\da-f]{1,6}\s?|\.))*)\s*\)/i
+CONSOLE MESSAGE: line 12: /foo\\bar\sbaz/i
+CONSOLE MESSAGE: line 13: /foo\\bar\sbaz/i
+CONSOLE MESSAGE: line 12: test
+CONSOLE MESSAGE: line 13: test
+CONSOLE MESSAGE: line 12: test named "test"
+CONSOLE MESSAGE: line 13: test named "test"
+CONSOLE MESSAGE: line 12: Error
+CONSOLE MESSAGE: line 13: Error
+CONSOLE MESSAGE: line 12: Error: my error message
+CONSOLE MESSAGE: line 13: Error: my error message
+CONSOLE MESSAGE: line 12: Error: my multiline
+error message
+CONSOLE MESSAGE: line 13: Error: my multiline
+error message
+CONSOLE MESSAGE: line 12: [object HTMLParagraphElement]
+CONSOLE MESSAGE: line 13: [object HTMLParagraphElement]
+CONSOLE MESSAGE: line 12: function () { return 1; }
+CONSOLE MESSAGE: line 13: function () { return 1; }
+CONSOLE MESSAGE: line 12: function () {
+        return 2;
+    }
+CONSOLE MESSAGE: line 13: function () {
+        return 2;
+    }
+CONSOLE MESSAGE: line 12: 0.12
+CONSOLE MESSAGE: line 13: 0.12
+CONSOLE MESSAGE: line 12: http://webkit.org/
+CONSOLE MESSAGE: line 13: http://webkit.org/
+CONSOLE MESSAGE: line 12: null
+CONSOLE MESSAGE: line 13: 
+CONSOLE MESSAGE: line 12: undefined
+CONSOLE MESSAGE: line 13: 
+CONSOLE MESSAGE: line 12: [object Attr]
+CONSOLE MESSAGE: line 13: [object Attr]
+CONSOLE MESSAGE: line 12: [object Attr]
+CONSOLE MESSAGE: line 13: [object Attr]
+CONSOLE MESSAGE: line 12: [object Attr]
+CONSOLE MESSAGE: line 13: [object Attr]
+CONSOLE MESSAGE: line 12: [object Object]
+CONSOLE MESSAGE: line 13: [object Object]
+CONSOLE MESSAGE: line 12: NaN
+CONSOLE MESSAGE: line 13: NaN
+CONSOLE MESSAGE: line 12: Infinity
+CONSOLE MESSAGE: line 13: Infinity
+CONSOLE MESSAGE: line 12: -Infinity
+CONSOLE MESSAGE: line 13: -Infinity
+CONSOLE MESSAGE: line 12: test,test2,,,test4,,,,,
+CONSOLE MESSAGE: line 13: test,test2,,,test4,,,,,
+CONSOLE MESSAGE: line 12: [object Object]
+CONSOLE MESSAGE: line 13: [object Object]
+CONSOLE MESSAGE: line 12: function () {}
+CONSOLE MESSAGE: line 13: function () {}
+CONSOLE MESSAGE: line 12: [object Object]
+CONSOLE MESSAGE: line 13: [object Object]
+CONSOLE MESSAGE: line 12: [object SVGSVGElement]
+CONSOLE MESSAGE: line 13: [object SVGSVGElement]
+CONSOLE MESSAGE: line 12: [object Object]
+CONSOLE MESSAGE: line 13: [object Object]
+CONSOLE MESSAGE: line 12: 0
+CONSOLE MESSAGE: line 13: 0
+CONSOLE MESSAGE: line 12: [object Object]
+CONSOLE MESSAGE: line 13: [object Object]
+CONSOLE MESSAGE: line 12: function Object() { [native code] }
+CONSOLE MESSAGE: line 13: function Object() { [native code] }
+CONSOLE MESSAGE: line 12: [object Object]
+CONSOLE MESSAGE: line 13: [object Object]
+CONSOLE MESSAGE: line 12: function ( /**/ foo/**/, /*/**/bar,
+    /**/baz) {}
+CONSOLE MESSAGE: line 13: function ( /**/ foo/**/, /*/**/bar,
+    /**/baz) {}
+CONSOLE MESSAGE: line 12: 42.0000
+CONSOLE MESSAGE: line 13: 42.0000
+CONSOLE MESSAGE: line 12: abc
+CONSOLE MESSAGE: line 13: abc
+CONSOLE MESSAGE: line 12: [object Uint16Array]
+CONSOLE MESSAGE: line 13: [object Uint16Array]
+CONSOLE MESSAGE: line 12: [object Text]
+CONSOLE MESSAGE: line 13: [object Text]
+CONSOLE MESSAGE: line 12: [object DOMException]
+CONSOLE MESSAGE: line 13: [object DOMException]
+CONSOLE MESSAGE: line 12: [object Uint8Array]
+CONSOLE MESSAGE: line 13: [object Uint8Array]
+CONSOLE MESSAGE: line 12: [object Uint8Array]
+CONSOLE MESSAGE: line 13: [object Uint8Array]
+CONSOLE MESSAGE: line 12: [object Uint8Array]
+CONSOLE MESSAGE: line 13: [object Uint8Array]
+CONSOLE MESSAGE: line 12: [object Object]
+CONSOLE MESSAGE: line 13: [object Object]
+CONSOLE MESSAGE: line 12: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
+CONSOLE MESSAGE: line 13: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
+CONSOLE MESSAGE: line 12: test
+CONSOLE MESSAGE: line 13: test
+Tests that console logging dumps proper messages.
+
+ console-format.html:22 Array(10)
+console-format.html:23 Array(10)
+console-format.html:24 Array(10)
+console-format.html:25 Test for zero "0" in formatter
+console-format.html:26 % self-escape1 dummy
+console-format.html:27 %s self-escape2 dummy
+console-format.html:28 %ss self-escape3 dummy
+console-format.html:29 %sdummy%s self-escape4
+console-format.html:30 %%% self-escape5 dummy
+console-format.html:31 %dummy self-escape6
+console-format.html:7 /^url\(\s*(?:(?:"(?:[^\\\"]|(?:\\[\da-f]{1,6}\s?|\.))*"|'(?:[^\\\']|(?:\\[\da-f]{1,6}\s?|\.))*')|(?:[!#$%&*-~\w]|(?:\\[\da-f]{1,6}\s?|\.))*)\s*\)/i
+console-format.html:8 [/^url\(\s*(?:(?:"(?:[^\\\"]|(?:\\[\da-f]{1,6}\s?|\…?:[!#$%&*-~\w]|(?:\\[\da-f]{1,6}\s?|\.))*)\s*\)/i]
+globals[0]
+/^url\(\s*(?:(?:"(?:[^\\\"]|(?:\\[\da-f]{1,6}\s?|\.))*"|'(?:[^\\\']|(?:\\[\da-f]{1,6}\s?|\.))*')|(?:[!#$%&*-~\w]|(?:\\[\da-f]{1,6}\s?|\.))*)\s*\)/i
+console-format.html:7 /foo\\bar\sbaz/i
+console-format.html:8 [/foo\\bar\sbaz/i]
+globals[1]
+/foo\\bar\sbaz/i
+console-format.html:7 test
+console-format.html:8 ["test"]
+globals[2]
+"test"
+console-format.html:7 test named "test"
+console-format.html:8 ["test named "test""]
+globals[3]
+"test named "test""
+console-format.html:7 Error
+console-format.html:8 [Error
+]
+globals[4]
+Error
+console-format.html:7 Error: my error message
+console-format.html:8 [Error: my error message
+]
+globals[5]
+Error: my error message
+console-format.html:7 Error: my multiline
+error message
+console-format.html:8 [Error: my multiline
+error message
+]
+globals[6]
+Error: my multiline
+error message
+console-format.html:7 
+    <p id="p">Tests that console logging dumps proper messages.</p>
+console-format.html:8 [p#p]
+globals[7]
+    <p id="p">Tests that console logging dumps proper messages.</p>
+console-format.html:7 ƒ () { return 1; }
+console-format.html:8 [ƒ]
+globals[8]
+ƒ () { return 1; }
+console-format.html:7 ƒ () {
+        return 2;
+    }
+console-format.html:8 [ƒ]
+globals[9]
+ƒ () {
+        return 2;
+    }
+console-format.html:7 0.12
+console-format.html:8 [0.12]
+globals[10]
+0.12
+console-format.html:7 http://webkit.org/
+console-format.html:8 ["http://webkit.org/"]
+globals[11]
+"http://webkit.org/"
+console-format.html:7 null
+console-format.html:8 [null]
+globals[12]
+null
+console-format.html:7 undefined
+console-format.html:8 [undefined]
+globals[13]
+undefined
+console-format.html:7 
+    attr=""
+console-format.html:8 [attr]
+globals[14]
+    attr=""
+console-format.html:7 
+    attr="value"
+console-format.html:8 [attr]
+globals[15]
+    attr="value"
+console-format.html:7 
+    id="x"
+console-format.html:8 [id]
+globals[16]
+    id="x"
+console-format.html:7 {}
+console-format.html:8 [{…}]
+globals[17]
+{}
+console-format.html:7 NaN
+console-format.html:8 [NaN]
+globals[18]
+NaN
+console-format.html:7 Infinity
+console-format.html:8 [Infinity]
+globals[19]
+Infinity
+console-format.html:7 -Infinity
+console-format.html:8 [-Infinity]
+globals[20]
+-Infinity
+console-format.html:7 (10) ["test", "test2", empty × 2, "test4", empty × 5, foo: {…}]
+console-format.html:8 [Array(10)]
+globals[21]
+(10) ["test", "test2", empty × 2, "test4", empty × 5, foo: {…}]
+console-format.html:7 {}
+console-format.html:8 [{…}]
+globals[22]
+{}
+console-format.html:7 [ƒ]
+console-format.html:8 [Array(1)]
+globals[23]
+[ƒ]
+console-format.html:7 {bar: "bar"}
+console-format.html:8 [{…}]
+globals[24]
+{bar: "bar"}
+console-format.html:7 
+    <svg id="svg-node"></svg>
+console-format.html:8 [svg#svg-node]
+globals[25]
+    <svg id="svg-node"></svg>
+console-format.html:7 {enumerableProp: 4, __underscoreEnumerableProp__: 5, __underscoreNonEnumerableProp: 2, abc: 3, getFoo: ƒ, …}
+console-format.html:8 [{…}]
+globals[26]
+{enumerableProp: 4, __underscoreEnumerableProp__: 5, __underscoreNonEnumerableProp: 2, abc: 3, getFoo: ƒ, …}
+console-format.html:7 -0
+console-format.html:8 [-0]
+globals[27]
+-0
+console-format.html:7 {}
+console-format.html:8 [{…}]
+globals[28]
+{}
+console-format.html:7 ƒ Object() { [native code] }
+console-format.html:8 [ƒ]
+globals[29]
+ƒ Object() { [native code] }
+console-format.html:7 {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
+console-format.html:8 [{…}]
+globals[30]
+{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
+console-format.html:7 ƒ ( /**/ foo/**/, /*/**/bar,
+    /**/baz) {}
+console-format.html:8 [ƒ]
+globals[31]
+ƒ ( /**/ foo/**/, /*/**/bar,
+    /**/baz) {}
+console-format.html:7 Number {[[PrimitiveValue]]: 42}
+console-format.html:8 [Number]
+globals[32]
+Number {[[PrimitiveValue]]: 42}
+console-format.html:7 String {[[PrimitiveValue]]: "abc"}
+console-format.html:8 [String]
+globals[33]
+String {[[PrimitiveValue]]: "abc"}
+console-format.html:7 Uint16Array(3) [1, 2, 3]
+console-format.html:8 [Uint16Array(3)]
+globals[34]
+Uint16Array(3) [1, 2, 3]
+console-format.html:7 #text
+console-format.html:8 [text]
+globals[35]
+#text
+console-format.html:7 DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.
+console-format.html:8 [DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of th…]
+globals[36]
+DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.
+console-format.html:7 Uint8Array [3]
+console-format.html:8 [Uint8Array(1)]
+globals[37]
+Uint8Array [3]
+console-format.html:7 Uint8Array(400) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …]
+console-format.html:8 [Uint8Array(400)]
+globals[38]
+Uint8Array(400) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …]
+console-format.html:7 Uint8Array(400000000) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …]
+console-format.html:8 [Uint8Array(400000000)]
+globals[39]
+Uint8Array(400000000) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …]
+console-format.html:7 namespace.longSubNamespace.x.className {}
+console-format.html:8 [n…e.l…e.x.className]
+globals[40]
+namespace.longSubNamespace.x.className {}
+console-format.html:7 (200) [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …]
+console-format.html:8 [Array(200)]
+globals[41]
+(200) [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …]
+console-format.html:7 ["test"]
+console-format.html:8 [Array(1)]
+globals[42]
+["test"]
+Expanded all messages
+console-format.html:22 Array(10)
+    0: "test"
+    1: "test2"
+    4: "test4"
+    foo: {}
+    length: 10
+    __proto__: Array(0)
+console-format.html:23 Array(10)
+    0: "test"
+    1: "test2"
+    4: "test4"
+    foo: {}
+    length: 10
+    __proto__: Array(0)
+console-format.html:24 Array(10)
+    0: "test"
+    1: "test2"
+    4: "test4"
+    foo: {}
+    length: 10
+    __proto__: Array(0)
+console-format.html:25 Test for zero "0" in formatter
+console-format.html:26 % self-escape1 dummy
+console-format.html:27 %s self-escape2 dummy
+console-format.html:28 %ss self-escape3 dummy
+console-format.html:29 %sdummy%s self-escape4
+console-format.html:30 %%% self-escape5 dummy
+console-format.html:31 %dummy self-escape6
+console-format.html:7 /^url\(\s*(?:(?:"(?:[^\\\"]|(?:\\[\da-f]{1,6}\s?|\.))*"|'(?:[^\\\']|(?:\\[\da-f]{1,6}\s?|\.))*')|(?:[!#$%&*-~\w]|(?:\\[\da-f]{1,6}\s?|\.))*)\s*\)/i
+console-format.html:8 [/^url\(\s*(?:(?:"(?:[^\\\"]|(?:\\[\da-f]{1,6}\s?|\…?:[!#$%&*-~\w]|(?:\\[\da-f]{1,6}\s?|\.))*)\s*\)/i]
+    0: /^url\(\s*(?:(?:"(?:[^\\\"]|(?:\\[\da-f]{1,6}\s?|\.))*"|'(?:[^\\\']|(?:\\[\da-f]{1,6}\s?|\.))*')|(?:[!#$%&*-~\w]|(?:\\[\da-f]{1,6}\s?|\.))*)\s*\)/i
+    length: 1
+    __proto__: Array(0)
+globals[0]
+/^url\(\s*(?:(?:"(?:[^\\\"]|(?:\\[\da-f]{1,6}\s?|\.))*"|'(?:[^\\\']|(?:\\[\da-f]{1,6}\s?|\.))*')|(?:[!#$%&*-~\w]|(?:\\[\da-f]{1,6}\s?|\.))*)\s*\)/i
+console-format.html:7 /foo\\bar\sbaz/i
+console-format.html:8 [/foo\\bar\sbaz/i]
+    0: /foo\\bar\sbaz/i
+    length: 1
+    __proto__: Array(0)
+globals[1]
+/foo\\bar\sbaz/i
+console-format.html:7 test
+console-format.html:8 ["test"]
+    0: "test"
+    length: 1
+    __proto__: Array(0)
+globals[2]
+"test"
+console-format.html:7 test named "test"
+console-format.html:8 ["test named "test""]
+    0: "test named "test""
+    length: 1
+    __proto__: Array(0)
+globals[3]
+"test named "test""
+console-format.html:7 Error
+console-format.html:8 [Error
+]
+    0: Error
+    length: 1
+    __proto__: Array(0)
+globals[4]
+Error
+console-format.html:7 Error: my error message
+console-format.html:8 [Error: my error message
+]
+    0: Error: my error message
+    length: 1
+    __proto__: Array(0)
+globals[5]
+Error: my error message
+console-format.html:7 Error: my multiline
+error message
+console-format.html:8 [Error: my multiline
+error message
+]
+    0: Error: my multiline
+error message
+    length: 1
+    __proto__: Array(0)
+globals[6]
+Error: my multiline
+error message
+console-format.html:7 
+    <p id="p">Tests that console logging dumps proper messages.</p>
+console-format.html:8 [p#p]
+    0: p#p
+    length: 1
+    __proto__: Array(0)
+globals[7]
+    <p id="p">Tests that console logging dumps proper messages.</p>
+console-format.html:7 ƒ () { return 1; }
+console-format.html:8 [ƒ]
+    0: ƒ ()
+    length: 1
+    __proto__: Array(0)
+globals[8]
+ƒ () { return 1; }
+console-format.html:7 ƒ () {
+        return 2;
+    }
+console-format.html:8 [ƒ]
+    0: ƒ ()
+    length: 1
+    __proto__: Array(0)
+globals[9]
+ƒ () {
+        return 2;
+    }
+console-format.html:7 0.12
+console-format.html:8 [0.12]
+    0: 0.12
+    length: 1
+    __proto__: Array(0)
+globals[10]
+0.12
+console-format.html:7 http://webkit.org/
+console-format.html:8 ["http://webkit.org/"]
+    0: "http://webkit.org/"
+    length: 1
+    __proto__: Array(0)
+globals[11]
+"http://webkit.org/"
+console-format.html:7 null
+console-format.html:8 [null]
+    0: null
+    length: 1
+    __proto__: Array(0)
+globals[12]
+null
+console-format.html:7 undefined
+console-format.html:8 [undefined]
+    0: undefined
+    length: 1
+    __proto__: Array(0)
+globals[13]
+undefined
+console-format.html:7 
+    attr=""
+console-format.html:8 [attr]
+    0: attr
+    length: 1
+    __proto__: Array(0)
+globals[14]
+    attr=""
+console-format.html:7 
+    attr="value"
+console-format.html:8 [attr]
+    0: attr
+    length: 1
+    __proto__: Array(0)
+globals[15]
+    attr="value"
+console-format.html:7 
+    id="x"
+console-format.html:8 [id]
+    0: id
+    length: 1
+    __proto__: Array(0)
+globals[16]
+    id="x"
+console-format.html:7 {}
+    length: (...)
+    get length: ƒ length()
+    __proto__: Object
+console-format.html:8 [{…}]
+    0: {}
+    length: 1
+    __proto__: Array(0)
+globals[17]
+{}
+    length: (...)
+    get length: ƒ length()
+    __proto__: Object
+console-format.html:7 NaN
+console-format.html:8 [NaN]
+    0: NaN
+    length: 1
+    __proto__: Array(0)
+globals[18]
+NaN
+console-format.html:7 Infinity
+console-format.html:8 [Infinity]
+    0: Infinity
+    length: 1
+    __proto__: Array(0)
+globals[19]
+Infinity
+console-format.html:7 -Infinity
+console-format.html:8 [-Infinity]
+    0: -Infinity
+    length: 1
+    __proto__: Array(0)
+globals[20]
+-Infinity
+console-format.html:7 (10) ["test", "test2", empty × 2, "test4", empty × 5, foo: {…}]
+    0: "test"
+    1: "test2"
+    4: "test4"
+    foo: {}
+    length: 10
+    __proto__: Array(0)
+console-format.html:8 [Array(10)]
+    0: (10) ["test", "test2", empty × 2, "test4", empty × 5, foo: {…}]
+    length: 1
+    __proto__: Array(0)
+globals[21]
+(10) ["test", "test2", empty × 2, "test4", empty × 5, foo: {…}]
+    0: "test"
+    1: "test2"
+    4: "test4"
+    foo: {}
+    length: 10
+    __proto__: Array(0)
+console-format.html:7 {}
+    __proto__: Object
+console-format.html:8 [{…}]
+    0: {}
+    length: 1
+    __proto__: Array(0)
+globals[22]
+{}
+    __proto__: Object
+console-format.html:7 [ƒ]
+    0: ƒ ()
+    length: 1
+    __proto__: Array(0)
+console-format.html:8 [Array(1)]
+    0: [ƒ]
+    length: 1
+    __proto__: Array(0)
+globals[23]
+[ƒ]
+    0: ƒ ()
+    length: 1
+    __proto__: Array(0)
+console-format.html:7 {bar: "bar"}
+    bar: "bar"
+    __proto__: Object
+console-format.html:8 [{…}]
+    0: {bar: "bar"}
+    length: 1
+    __proto__: Array(0)
+globals[24]
+{bar: "bar"}
+    bar: "bar"
+    __proto__: Object
+console-format.html:7 
+    <svg id="svg-node"></svg>
+console-format.html:8 [svg#svg-node]
+    0: svg#svg-node
+    length: 1
+    __proto__: Array(0)
+globals[25]
+    <svg id="svg-node"></svg>
+console-format.html:7 {enumerableProp: 4, __underscoreEnumerableProp__: 5, __underscoreNonEnumerableProp: 2, abc: 3, getFoo: ƒ, …}
+    enumerableProp: 4
+    __underscoreEnumerableProp__: 5
+    abc: 3
+    bar: (...)
+    getFoo: ƒ ()
+    __underscoreNonEnumerableProp: 2
+    get bar: ƒ ()
+    set bar: ƒ (x)
+    __proto__: Object
+console-format.html:8 [{…}]
+    0: {enumerableProp: 4, __underscoreEnumerableProp__: 5, __underscoreNonEnumerableProp: 2, abc: 3, getFoo: ƒ, …}
+    length: 1
+    __proto__: Array(0)
+globals[26]
+{enumerableProp: 4, __underscoreEnumerableProp__: 5, __underscoreNonEnumerableProp: 2, abc: 3, getFoo: ƒ, …}
+    enumerableProp: 4
+    __underscoreEnumerableProp__: 5
+    abc: 3
+    bar: (...)
+    getFoo: ƒ ()
+    __underscoreNonEnumerableProp: 2
+    get bar: ƒ ()
+    set bar: ƒ (x)
+    __proto__: Object
+console-format.html:7 -0
+console-format.html:8 [-0]
+    0: -0
+    length: 1
+    __proto__: Array(0)
+globals[27]
+-0
+console-format.html:7 {}
+    No properties
+console-format.html:8 [{…}]
+    0: {}
+    length: 1
+    __proto__: Array(0)
+globals[28]
+{}
+    No properties
+console-format.html:7 ƒ Object() { [native code] }
+console-format.html:8 [ƒ]
+    0: ƒ Object()
+    length: 1
+    __proto__: Array(0)
+globals[29]
+ƒ Object() { [native code] }
+console-format.html:7 {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
+    constructor: ƒ Object()
+    hasOwnProperty: ƒ hasOwnProperty()
+    isPrototypeOf: ƒ isPrototypeOf()
+    propertyIsEnumerable: ƒ propertyIsEnumerable()
+    toLocaleString: ƒ toLocaleString()
+    toString: ƒ toString()
+    valueOf: ƒ valueOf()
+    __defineGetter__: ƒ __defineGetter__()
+    __defineSetter__: ƒ __defineSetter__()
+    __lookupGetter__: ƒ __lookupGetter__()
+    __lookupSetter__: ƒ __lookupSetter__()
+    get __proto__: ƒ __proto__()
+    set __proto__: ƒ __proto__()
+console-format.html:8 [{…}]
+    0: {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
+    length: 1
+    __proto__: Array(0)
+globals[30]
+{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
+    constructor: ƒ Object()
+    hasOwnProperty: ƒ hasOwnProperty()
+    isPrototypeOf: ƒ isPrototypeOf()
+    propertyIsEnumerable: ƒ propertyIsEnumerable()
+    toLocaleString: ƒ toLocaleString()
+    toString: ƒ toString()
+    valueOf: ƒ valueOf()
+    __defineGetter__: ƒ __defineGetter__()
+    __defineSetter__: ƒ __defineSetter__()
+    __lookupGetter__: ƒ __lookupGetter__()
+    __lookupSetter__: ƒ __lookupSetter__()
+    get __proto__: ƒ __proto__()
+    set __proto__: ƒ __proto__()
+console-format.html:7 ƒ ( /**/ foo/**/, /*/**/bar,
+    /**/baz) {}
+console-format.html:8 [ƒ]
+    0: ƒ ( /**/ foo/**/, /*/**/bar,     /**/baz)
+    length: 1
+    __proto__: Array(0)
+globals[31]
+ƒ ( /**/ foo/**/, /*/**/bar,
+    /**/baz) {}
+console-format.html:7 Number {[[PrimitiveValue]]: 42}
+    __proto__: Number
+    [[PrimitiveValue]]: 42
+console-format.html:8 [Number]
+    0: Number {[[PrimitiveValue]]: 42}
+    length: 1
+    __proto__: Array(0)
+globals[32]
+Number {[[PrimitiveValue]]: 42}
+    __proto__: Number
+    [[PrimitiveValue]]: 42
+console-format.html:7 String {[[PrimitiveValue]]: "abc"}
+    0: "a"
+    1: "b"
+    2: "c"
+    length: 3
+    __proto__: String
+    [[PrimitiveValue]]: "abc"
+console-format.html:8 [String]
+    0: String {[[PrimitiveValue]]: "abc"}
+    length: 1
+    __proto__: Array(0)
+globals[33]
+String {[[PrimitiveValue]]: "abc"}
+    0: "a"
+    1: "b"
+    2: "c"
+    length: 3
+    __proto__: String
+    [[PrimitiveValue]]: "abc"
+console-format.html:7 Uint16Array(3) [1, 2, 3]
+    0: 1
+    1: 2
+    2: 3
+    buffer: (...)
+    byteLength: (...)
+    byteOffset: (...)
+    length: (...)
+    Symbol(Symbol.toStringTag): (...)
+    __proto__: TypedArray
+console-format.html:8 [Uint16Array(3)]
+    0: Uint16Array(3) [1, 2, 3]
+    length: 1
+    __proto__: Array(0)
+globals[34]
+Uint16Array(3) [1, 2, 3]
+    0: 1
+    1: 2
+    2: 3
+    buffer: (...)
+    byteLength: (...)
+    byteOffset: (...)
+    length: (...)
+    Symbol(Symbol.toStringTag): (...)
+    __proto__: TypedArray
+console-format.html:7 #text
+console-format.html:8 [text]
+    0: text
+    length: 1
+    __proto__: Array(0)
+globals[35]
+#text
+console-format.html:7 DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.
+console-format.html:8 [DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of th…]
+    0: DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.
+    length: 1
+    __proto__: Array(0)
+globals[36]
+DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.
+console-format.html:7 Uint8Array [3]
+    0: 3
+    buffer: (...)
+    byteLength: (...)
+    byteOffset: (...)
+    length: (...)
+    Symbol(Symbol.toStringTag): (...)
+    __proto__: TypedArray
+console-format.html:8 [Uint8Array(1)]
+    0: Uint8Array [3]
+    length: 1
+    __proto__: Array(0)
+globals[37]
+Uint8Array [3]
+    0: 3
+    buffer: (...)
+    byteLength: (...)
+    byteOffset: (...)
+    length: (...)
+    Symbol(Symbol.toStringTag): (...)
+    __proto__: TypedArray
+console-format.html:7 Uint8Array(400) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …]
+    [0 … 99]
+    [100 … 199]
+    [200 … 299]
+    [300 … 399]
+    foo: "bar"
+    __proto__: TypedArray
+console-format.html:8 [Uint8Array(400)]
+    0: Uint8Array(400) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …]
+    length: 1
+    __proto__: Array(0)
+globals[38]
+Uint8Array(400) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …]
+    [0 … 99]
+    [100 … 199]
+    [200 … 299]
+    [300 … 399]
+    foo: "bar"
+    __proto__: TypedArray
+console-format.html:7 Uint8Array(400000000) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …]
+    [0 … 99999999]
+    [100000000 … 199999999]
+    [200000000 … 299999999]
+    [300000000 … 399999999]
+    __proto__: TypedArray
+console-format.html:8 [Uint8Array(400000000)]
+    0: Uint8Array(400000000) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …]
+    length: 1
+    __proto__: Array(0)
+globals[39]
+Uint8Array(400000000) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …]
+    [0 … 99999999]
+    [100000000 … 199999999]
+    [200000000 … 299999999]
+    [300000000 … 399999999]
+    __proto__: TypedArray
+console-format.html:7 namespace.longSubNamespace.x.className {}
+    __proto__: Object
+console-format.html:8 [n…e.l…e.x.className]
+    0: namespace.longSubNamespace.x.className {}
+    length: 1
+    __proto__: Array(0)
+globals[40]
+namespace.longSubNamespace.x.className {}
+    __proto__: Object
+console-format.html:7 (200) [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …]
+    [0 … 99]
+    [100 … 199]
+    length: 200
+    __proto__: Array(0)
+console-format.html:8 [Array(200)]
+    0: (200) [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …]
+    length: 1
+    __proto__: Array(0)
+globals[41]
+(200) [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …]
+    [0 … 99]
+    [100 … 199]
+    length: 200
+    __proto__: Array(0)
+console-format.html:7 ["test"]
+    0: "test"
+    length: 1
+    __proto__: Array(0)
+console-format.html:8 [Array(1)]
+    0: ["test"]
+    length: 1
+    __proto__: Array(0)
+globals[42]
+["test"]
+    0: "test"
+    length: 1
+    __proto__: Array(0)
+
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/canvas-composite-repaint-by-all-imagesource-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/canvas-composite-repaint-by-all-imagesource-expected.txt
index 97e19398..6a05e10 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/canvas-composite-repaint-by-all-imagesource-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/canvas-composite-repaint-by-all-imagesource-expected.txt
@@ -235,8 +235,7 @@
       "bounds": [150, 60]
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutFlexibleBox (relative positioned) DIV",
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/composited-table-row-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/composited-table-row-expected.txt
index 15a6444..47c3340 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/composited-table-row-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/composited-table-row-expected.txt
@@ -9,7 +9,6 @@
     {
       "name": "LayoutTableRow TR",
       "position": [8, 8],
-      "transformOrigin": [36.5, 11.5],
       "bounds": [74, 24],
       "drawsContent": true,
       "backgroundColor": "#FF0000",
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/overflow-scroll-local-background-text-color-change-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/overflow-scroll-local-background-text-color-change-expected.txt
deleted file mode 100644
index 1df54e65..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/overflow-scroll-local-background-text-color-change-expected.txt
+++ /dev/null
@@ -1,93 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true
-    },
-    {
-      "name": "LayoutBlockFlow DIV id='scroller'",
-      "position": [8, 8],
-      "bounds": [200, 200],
-      "shouldFlattenTransform": false,
-      "drawsContent": true,
-      "backgroundColor": "#0000FF",
-      "paintInvalidations": [
-        {
-          "object": "LayoutBlockFlow DIV id='scroller'",
-          "rect": [0, 0, 200, 200],
-          "reason": "style change"
-        }
-      ]
-    },
-    {
-      "name": "Scrolling Layer",
-      "bounds": [185, 185],
-      "shouldFlattenTransform": false
-    },
-    {
-      "name": "Scrolling Contents Layer",
-      "bounds": [185, 552],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutBlockFlow DIV id='scroller'",
-          "rect": [0, 0, 185, 552],
-          "reason": "background on scrolling contents layer"
-        }
-      ]
-    },
-    {
-      "name": "Overflow Controls Host Layer",
-      "bounds": [200, 200]
-    },
-    {
-      "name": "Horizontal Scrollbar Layer",
-      "position": [0, 185],
-      "bounds": [185, 15],
-      "paintInvalidations": [
-        {
-          "object": "Horizontal Scrollbar Layer",
-          "rect": [0, 0, 185, 15],
-          "reason": "full"
-        }
-      ]
-    },
-    {
-      "name": "Vertical Scrollbar Layer",
-      "position": [185, 0],
-      "bounds": [15, 185],
-      "paintInvalidations": [
-        {
-          "object": "Vertical Scrollbar Layer",
-          "rect": [0, 0, 15, 185],
-          "reason": "full"
-        },
-        {
-          "object": "Vertical Scrollbar Layer",
-          "rect": [0, 0, 15, 185],
-          "reason": "full"
-        }
-      ]
-    },
-    {
-      "name": "Scroll Corner Layer",
-      "position": [185, 185],
-      "bounds": [15, 15],
-      "drawsContent": true
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "Scrolling Contents Layer",
-      "reason": "background on scrolling contents layer"
-    },
-    {
-      "object": "LayoutBlockFlow DIV id='scroller'",
-      "reason": "style change"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/selection/selection-within-composited-scroller-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/selection/selection-within-composited-scroller-expected.txt
deleted file mode 100644
index 800e803b..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/selection/selection-within-composited-scroller-expected.txt
+++ /dev/null
@@ -1,83 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true
-    },
-    {
-      "name": "LayoutBlockFlow DIV id='scroller'",
-      "position": [8, 8],
-      "bounds": [200, 200],
-      "shouldFlattenTransform": false,
-      "drawsContent": true,
-      "backgroundColor": "#D3D3D3"
-    },
-    {
-      "name": "Scrolling Layer",
-      "bounds": [185, 185],
-      "shouldFlattenTransform": false
-    },
-    {
-      "name": "Scrolling Contents Layer",
-      "bounds": [200, 1620],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutText #text",
-          "rect": [0, 610, 21, 19],
-          "reason": "selection"
-        }
-      ]
-    },
-    {
-      "name": "Overflow Controls Host Layer",
-      "bounds": [200, 200]
-    },
-    {
-      "name": "Horizontal Scrollbar Layer",
-      "position": [0, 185],
-      "bounds": [185, 15]
-    },
-    {
-      "name": "Vertical Scrollbar Layer",
-      "position": [185, 0],
-      "bounds": [15, 185]
-    },
-    {
-      "name": "Scroll Corner Layer",
-      "position": [185, 185],
-      "bounds": [15, 15],
-      "drawsContent": true
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutBlockFlow HTML",
-      "reason": "selection"
-    },
-    {
-      "object": "LayoutBlockFlow BODY",
-      "reason": "selection"
-    },
-    {
-      "object": "LayoutBlockFlow DIV id='scroller'",
-      "reason": "selection"
-    },
-    {
-      "object": "LayoutBlockFlow DIV id='target'",
-      "reason": "selection"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "selection"
-    },
-    {
-      "object": "InlineTextBox 'test'",
-      "reason": "selection"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/table/composited-table-background-composited-row-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/table/composited-table-background-composited-row-expected.txt
index 8e0f5005..86f5064 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/table/composited-table-background-composited-row-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/table/composited-table-background-composited-row-expected.txt
@@ -22,7 +22,7 @@
     },
     {
       "name": "LayoutTableCell TD",
-      "position": [64, 0],
+      "position": [72, 96],
       "bounds": [59, 64],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/table/composited-table-background-composited-row-initial-empty-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/table/composited-table-background-composited-row-initial-empty-expected.txt
index 8e0f5005..86f5064 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/table/composited-table-background-composited-row-initial-empty-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/table/composited-table-background-composited-row-initial-empty-expected.txt
@@ -22,7 +22,7 @@
     },
     {
       "name": "LayoutTableCell TD",
-      "position": [64, 0],
+      "position": [72, 96],
       "bounds": [59, 64],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/table/composited-table-background-section-composited-row-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/table/composited-table-background-section-composited-row-expected.txt
index 576d0d4e..41c7dd4f 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/table/composited-table-background-section-composited-row-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/table/composited-table-background-section-composited-row-expected.txt
@@ -22,13 +22,13 @@
     },
     {
       "name": "LayoutTableRow TR",
-      "position": [0, 68],
+      "position": [8, 96],
       "bounds": [186, 64],
       "drawsContent": true
     },
     {
       "name": "LayoutTableCell TD",
-      "position": [64, 0],
+      "position": [72, 96],
       "bounds": [59, 64],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/table/composited-table-background-section-composited-row-initial-empty-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/table/composited-table-background-section-composited-row-initial-empty-expected.txt
index 576d0d4e..41c7dd4f 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/table/composited-table-background-section-composited-row-initial-empty-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/table/composited-table-background-section-composited-row-initial-empty-expected.txt
@@ -22,13 +22,13 @@
     },
     {
       "name": "LayoutTableRow TR",
-      "position": [0, 68],
+      "position": [8, 96],
       "bounds": [186, 64],
       "drawsContent": true
     },
     {
       "name": "LayoutTableCell TD",
-      "position": [64, 0],
+      "position": [72, 96],
       "bounds": [59, 64],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/table/composited-table-background-section-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/table/composited-table-background-section-expected.txt
index f604f53..053e101e 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/table/composited-table-background-section-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/table/composited-table-background-section-expected.txt
@@ -22,7 +22,7 @@
     },
     {
       "name": "LayoutTableCell TD",
-      "position": [64, 68],
+      "position": [72, 96],
       "bounds": [59, 64],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/table/composited-table-background-section-initial-empty-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/table/composited-table-background-section-initial-empty-expected.txt
index f604f53..053e101e 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/table/composited-table-background-section-initial-empty-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/table/composited-table-background-section-initial-empty-expected.txt
@@ -22,7 +22,7 @@
     },
     {
       "name": "LayoutTableCell TD",
-      "position": [64, 68],
+      "position": [72, 96],
       "bounds": [59, 64],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/video-paint-invalidation-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/video-paint-invalidation-expected.txt
new file mode 100644
index 0000000..9fa92010
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/video-paint-invalidation-expected.txt
@@ -0,0 +1,38 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true
+    },
+    {
+      "name": "LayoutVideo VIDEO id='video'",
+      "position": [8, 8],
+      "bounds": [320, 240]
+    },
+    {
+      "name": "Squashing Containment Layer",
+      "shouldFlattenTransform": false
+    },
+    {
+      "name": "LayoutFlexibleBox (relative positioned) DIV",
+      "position": [8, 8],
+      "bounds": [320, 240],
+      "drawsContent": true
+    },
+    {
+      "name": "Squashing Layer (first squashed layer: LayoutFlexibleBox (relative positioned) DIV)",
+      "position": [8, 8],
+      "bounds": [320, 240],
+      "drawsContent": true
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutVideo VIDEO id='video'",
+      "reason": "full"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/markers/suggestion-marker-basic-expected.png b/third_party/WebKit/LayoutTests/platform/linux/paint/markers/suggestion-marker-basic-expected.png
new file mode 100644
index 0000000..ebcf20a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/markers/suggestion-marker-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/markers/suggestion-marker-basic-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/markers/suggestion-marker-basic-expected.txt
new file mode 100644
index 0000000..7947f7d8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/markers/suggestion-marker-basic-expected.txt
@@ -0,0 +1,102 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x460
+  LayoutBlockFlow {HTML} at (0,0) size 800x460
+    LayoutBlockFlow {BODY} at (8,8) size 784x0
+      LayoutBlockFlow (floating) {DIV} at (586,0) size 198x192
+        LayoutBlockFlow {P} at (0,16) size 198x20
+          LayoutText {#text} at (167,0) size 31x19
+            text run at (167,0) width 31: "RTL"
+        LayoutBlockFlow {DIV} at (0,52) size 198x20
+          LayoutText {#text} at (127,0) size 71x19
+            text run at (127,0) width 71: "markRtlAll"
+        LayoutBlockFlow {DIV} at (0,72) size 198x20
+          LayoutText {#text} at (90,0) size 108x19
+            text run at (90,0) width 108: "markRtlAllThick"
+        LayoutBlockFlow {DIV} at (0,92) size 198x20
+          LayoutText {#text} at (81,0) size 117x19
+            text run at (81,0) width 117: "markRtlBeginning"
+        LayoutBlockFlow {DIV} at (0,112) size 198x20
+          LayoutText {#text} at (0,0) size 198x19
+            text run at (0,0) width 198: "markRtlAllExceptFirstAndLast"
+        LayoutBlockFlow {DIV} at (0,132) size 198x20
+          LayoutText {#text} at (121,0) size 77x19
+            text run at (121,0) width 77: "markRtlEnd"
+        LayoutBlockFlow {DIV} at (0,152) size 198x40
+          LayoutBlockFlow {DIV} at (0,0) size 198x20
+            LayoutText {#text} at (147,0) size 32x19
+              text run at (147,0) width 32: "mark"
+            LayoutInline {SPAN} at (0,0) size 19x19
+              LayoutText {#text} at (179,0) size 19x19
+                text run at (179,0) width 19: "Rtl"
+          LayoutBlockFlow {DIV} at (0,20) size 198x20
+            LayoutText {#text} at (113,0) size 85x19
+              text run at (113,0) width 85: "AcrossNodes"
+      LayoutBlockFlow (floating) {DIV} at (0,0) size 331x452
+        LayoutBlockFlow {P} at (0,16) size 331x20
+          LayoutText {#text} at (0,0) size 30x19
+            text run at (0,0) width 30: "LTR"
+        LayoutBlockFlow {DIV} at (0,52) size 331x20
+          LayoutText {#text} at (0,0) size 52x19
+            text run at (0,0) width 52: "markAll"
+        LayoutBlockFlow {DIV} at (0,72) size 331x20
+          LayoutText {#text} at (0,0) size 89x19
+            text run at (0,0) width 89: "markAllThick"
+        LayoutBlockFlow {DIV} at (0,92) size 331x20
+          LayoutText {#text} at (0,0) size 151x19
+            text run at (0,0) width 151: "markAllDifferentColors"
+        LayoutBlockFlow {DIV} at (0,112) size 331x20
+          LayoutText {#text} at (0,0) size 98x19
+            text run at (0,0) width 98: "markBeginning"
+        LayoutBlockFlow {DIV} at (0,132) size 331x20
+          LayoutText {#text} at (0,0) size 179x19
+            text run at (0,0) width 179: "markAllExceptFirstAndLast"
+        LayoutBlockFlow {DIV} at (0,152) size 331x20
+          LayoutText {#text} at (0,0) size 58x19
+            text run at (0,0) width 58: "markEnd"
+        LayoutBlockFlow {DIV} at (0,172) size 331x20
+          LayoutText {#text} at (0,0) size 114x19
+            text run at (0,0) width 114: "markNothingZero"
+        LayoutBlockFlow {DIV} at (0,192) size 331x20
+          LayoutText {#text} at (0,0) size 110x19
+            text run at (0,0) width 110: "markNothingEnd"
+        LayoutBlockFlow {DIV} at (0,212) size 331x40
+          LayoutBlockFlow {DIV} at (0,0) size 331x20
+            LayoutText {#text} at (0,0) size 32x19
+              text run at (0,0) width 32: "mark"
+            LayoutInline {SPAN} at (0,0) size 44x19
+              LayoutText {#text} at (32,0) size 44x19
+                text run at (32,0) width 44: "Across"
+          LayoutBlockFlow {DIV} at (0,20) size 331x20
+            LayoutText {#text} at (0,0) size 41x19
+              text run at (0,0) width 41: "Nodes"
+        LayoutBlockFlow {DIV} at (0,252) size 331x20
+          LayoutText {#text} at (0,0) size 245x19
+            text run at (0,0) width 245: "overridingSpellingMarkerAtBeginning"
+        LayoutBlockFlow {DIV} at (0,272) size 331x20
+          LayoutText {#text} at (0,0) size 205x19
+            text run at (0,0) width 205: "overridingSpellingMarkerAtEnd"
+        LayoutBlockFlow {DIV} at (0,292) size 331x20
+          LayoutText {#text} at (0,0) size 302x19
+            text run at (0,0) width 302: "overridingSpellingMarkerIntersectingBeginning"
+        LayoutBlockFlow {DIV} at (0,312) size 331x20
+          LayoutText {#text} at (0,0) size 262x19
+            text run at (0,0) width 262: "overridingSpellingMarkerIntersectingEnd"
+        LayoutBlockFlow {DIV} at (0,332) size 331x20
+          LayoutText {#text} at (0,0) size 253x19
+            text run at (0,0) width 253: "notOverridingSpellingMarkersTouching"
+        LayoutBlockFlow {DIV} at (0,352) size 331x20
+          LayoutText {#text} at (0,0) size 274x19
+            text run at (0,0) width 274: "overridingCompositionMarkerAtBeginning"
+        LayoutBlockFlow {DIV} at (0,372) size 331x20
+          LayoutText {#text} at (0,0) size 234x19
+            text run at (0,0) width 234: "overridingCompositionMarkerAtEnd"
+        LayoutBlockFlow {DIV} at (0,392) size 331x20
+          LayoutText {#text} at (0,0) size 331x19
+            text run at (0,0) width 331: "overridingCompositionMarkerIntersectingBeginning"
+        LayoutBlockFlow {DIV} at (0,412) size 331x20
+          LayoutText {#text} at (0,0) size 291x19
+            text run at (0,0) width 291: "overridingCompositionMarkerIntersectingEnd"
+        LayoutBlockFlow {DIV} at (0,432) size 331x20
+          LayoutText {#text} at (0,0) size 282x19
+            text run at (0,0) width 282: "notOverridingCompositionMarkersTouching"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/markers/suggestion-marker-split-expected.png b/third_party/WebKit/LayoutTests/platform/linux/paint/markers/suggestion-marker-split-expected.png
new file mode 100644
index 0000000..862e08f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/markers/suggestion-marker-split-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/markers/suggestion-marker-split-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/markers/suggestion-marker-split-expected.txt
new file mode 100644
index 0000000..e0b85f30
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/markers/suggestion-marker-split-expected.txt
@@ -0,0 +1,20 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x56
+  LayoutBlockFlow {HTML} at (0,0) size 800x56
+    LayoutBlockFlow {BODY} at (8,8) size 784x40
+      LayoutBlockFlow {DIV} at (0,0) size 784x20
+        LayoutText {#text} at (0,0) size 22x19
+          text run at (0,0) width 22: "abc"
+        LayoutText {#text} at (22,0) size 32x19
+          text run at (22,0) width 32: " xxx "
+        LayoutText {#text} at (54,0) size 20x19
+          text run at (54,0) width 20: "def"
+layer at (8,28) size 128x20 scrollWidth 160
+  LayoutBlockFlow {DIV} at (0,20) size 128x20
+    LayoutText {#text} at (0,0) size 62x19
+      text run at (0,0) width 62: "abcdefghi"
+    LayoutText {#text} at (62,0) size 32x19
+      text run at (62,0) width 32: " xxx "
+    LayoutText {#text} at (94,0) size 65x19
+      text run at (94,0) width 65: "jklmnopqr"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-mime-types.https-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-mime-types.https-expected.txt
new file mode 100644
index 0000000..28bf3a7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-mime-types.https-expected.txt
@@ -0,0 +1,39 @@
+This is a testharness.js-based test.
+FAIL Registering script with no MIME type Test bug: need to pass exception to assert_throws()
+FAIL Registering script with bad MIME type Test bug: need to pass exception to assert_throws()
+FAIL Registering script that imports script with no MIME type assert_unreached: Should have rejected: Registration of no MIME type imported script should fail. Reached unreachable code
+FAIL Registering script that imports script with bad MIME type assert_unreached: Should have rejected: Registration of plain text imported script should fail. Reached unreachable code
+FAIL Registering script with good MIME type application/ecmascript promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type application/ecmascript
+PASS Registering script with good MIME type application/javascript
+PASS Registering script that imports script with good MIME type application/javascript
+FAIL Registering script with good MIME type application/x-ecmascript promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type application/x-ecmascript
+PASS Registering script with good MIME type application/x-javascript
+PASS Registering script that imports script with good MIME type application/x-javascript
+FAIL Registering script with good MIME type text/ecmascript promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/ecmascript
+PASS Registering script with good MIME type text/javascript
+PASS Registering script that imports script with good MIME type text/javascript
+FAIL Registering script with good MIME type text/javascript1.0 promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/javascript1.0
+FAIL Registering script with good MIME type text/javascript1.1 promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/javascript1.1
+FAIL Registering script with good MIME type text/javascript1.2 promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/javascript1.2
+FAIL Registering script with good MIME type text/javascript1.3 promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/javascript1.3
+FAIL Registering script with good MIME type text/javascript1.4 promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/javascript1.4
+FAIL Registering script with good MIME type text/javascript1.5 promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/javascript1.5
+FAIL Registering script with good MIME type text/jscript promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/jscript
+FAIL Registering script with good MIME type text/livescript promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/livescript
+FAIL Registering script with good MIME type text/x-ecmascript promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/x-ecmascript
+FAIL Registering script with good MIME type text/x-javascript promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/x-javascript
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-scope.https-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-scope.https-expected.txt
new file mode 100644
index 0000000..c2ebe84
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-scope.https-expected.txt
@@ -0,0 +1,11 @@
+This is a testharness.js-based test.
+FAIL Scope including URL-encoded slash Test bug: need to pass exception to assert_throws()
+FAIL Scope including URL-encoded backslash Test bug: need to pass exception to assert_throws()
+PASS Scope including URL-encoded multibyte characters
+PASS Scope including non-escaped multibyte characters
+PASS Scope including self-reference
+PASS Scope including parent-reference
+PASS Scope including consecutive slashes
+FAIL Scope URL is same-origin filesystem: URL Test bug: need to pass exception to assert_throws()
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-script-url.https-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-script-url.https-expected.txt
new file mode 100644
index 0000000..ce29087
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-script-url.https-expected.txt
@@ -0,0 +1,9 @@
+This is a testharness.js-based test.
+FAIL Script URL including URL-encoded slash Test bug: need to pass exception to assert_throws()
+FAIL Script URL including uppercase URL-encoded slash Test bug: need to pass exception to assert_throws()
+FAIL Script URL including URL-encoded backslash Test bug: need to pass exception to assert_throws()
+FAIL Script URL including uppercase URL-encoded backslash Test bug: need to pass exception to assert_throws()
+PASS Script URL including self-reference
+PASS Script URL including parent-reference
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-script.https-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-script.https-expected.txt
new file mode 100644
index 0000000..1dbf650
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-script.https-expected.txt
@@ -0,0 +1,12 @@
+This is a testharness.js-based test.
+FAIL Registering invalid chunked encoding script Test bug: need to pass exception to assert_throws()
+FAIL Registering invalid chunked encoding script with flush Test bug: need to pass exception to assert_throws()
+FAIL Registering script including parse error Test bug: need to pass exception to assert_throws()
+FAIL Registering script including undefined error Test bug: need to pass exception to assert_throws()
+FAIL Registering script including uncaught exception Test bug: need to pass exception to assert_throws()
+FAIL Registering script importing malformed script Test bug: need to pass exception to assert_throws()
+FAIL Registering non-existent script Test bug: need to pass exception to assert_throws()
+FAIL Registering script importing non-existent script Test bug: need to pass exception to assert_throws()
+PASS Registering script including caught exception
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-security-error.https-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-security-error.https-expected.txt
new file mode 100644
index 0000000..742add3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-security-error.https-expected.txt
@@ -0,0 +1,11 @@
+This is a testharness.js-based test.
+FAIL Registering same scope as the script directory without the last slashTest bug: need to pass exception to assert_throws()
+FAIL Registration scope outside the script directoryTest bug: need to pass exception to assert_throws()
+FAIL Registering scope outside domainTest bug: need to pass exception to assert_throws()
+FAIL Registering script outside domainTest bug: need to pass exception to assert_throws()
+FAIL Registering redirected scriptTest bug: need to pass exception to assert_throws()
+FAIL Scope including parent-reference and not under the script directoryTest bug: need to pass exception to assert_throws()
+FAIL Script URL including consecutive slashesTest bug: need to pass exception to assert_throws()
+FAIL Script URL is same-origin filesystem: URLTest bug: need to pass exception to assert_throws()
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-blobs/external/wpt/service-workers/service-worker/registration-mime-types.https-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-blobs/external/wpt/service-workers/service-worker/registration-mime-types.https-expected.txt
new file mode 100644
index 0000000..e4d2ccd0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-blobs/external/wpt/service-workers/service-worker/registration-mime-types.https-expected.txt
@@ -0,0 +1,39 @@
+This is a testharness.js-based test.
+PASS Registering script with no MIME type
+PASS Registering script with bad MIME type
+FAIL Registering script that imports script with no MIME type assert_unreached: Should have rejected: Registration of no MIME type imported script should fail. Reached unreachable code
+FAIL Registering script that imports script with bad MIME type assert_unreached: Should have rejected: Registration of plain text imported script should fail. Reached unreachable code
+FAIL Registering script with good MIME type application/ecmascript promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('application/ecmascript')."
+PASS Registering script that imports script with good MIME type application/ecmascript
+PASS Registering script with good MIME type application/javascript
+PASS Registering script that imports script with good MIME type application/javascript
+FAIL Registering script with good MIME type application/x-ecmascript promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('application/x-ecmascript')."
+PASS Registering script that imports script with good MIME type application/x-ecmascript
+PASS Registering script with good MIME type application/x-javascript
+PASS Registering script that imports script with good MIME type application/x-javascript
+FAIL Registering script with good MIME type text/ecmascript promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/ecmascript')."
+PASS Registering script that imports script with good MIME type text/ecmascript
+PASS Registering script with good MIME type text/javascript
+PASS Registering script that imports script with good MIME type text/javascript
+FAIL Registering script with good MIME type text/javascript1.0 promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/javascript1.0')."
+PASS Registering script that imports script with good MIME type text/javascript1.0
+FAIL Registering script with good MIME type text/javascript1.1 promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/javascript1.1')."
+PASS Registering script that imports script with good MIME type text/javascript1.1
+FAIL Registering script with good MIME type text/javascript1.2 promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/javascript1.2')."
+PASS Registering script that imports script with good MIME type text/javascript1.2
+FAIL Registering script with good MIME type text/javascript1.3 promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/javascript1.3')."
+PASS Registering script that imports script with good MIME type text/javascript1.3
+FAIL Registering script with good MIME type text/javascript1.4 promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/javascript1.4')."
+PASS Registering script that imports script with good MIME type text/javascript1.4
+FAIL Registering script with good MIME type text/javascript1.5 promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/javascript1.5')."
+PASS Registering script that imports script with good MIME type text/javascript1.5
+FAIL Registering script with good MIME type text/jscript promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/jscript')."
+PASS Registering script that imports script with good MIME type text/jscript
+FAIL Registering script with good MIME type text/livescript promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/livescript')."
+PASS Registering script that imports script with good MIME type text/livescript
+FAIL Registering script with good MIME type text/x-ecmascript promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/x-ecmascript')."
+PASS Registering script that imports script with good MIME type text/x-ecmascript
+FAIL Registering script with good MIME type text/x-javascript promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/x-javascript')."
+PASS Registering script that imports script with good MIME type text/x-javascript
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-loading/http/tests/devtools/console/console-uncaught-promise-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-loading/http/tests/devtools/console/console-uncaught-promise-expected.txt
index cd25fb0..1c491ab 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-loading/http/tests/devtools/console/console-uncaught-promise-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-loading/http/tests/devtools/console/console-uncaught-promise-expected.txt
@@ -74,6 +74,7 @@
 setTimeout (async)
 runNextPromiseTest @ console-uncaught-promise.html:15
 (anonymous) @ VM:1
+A bad HTTP response code (404) was received when fetching the script.
 console-uncaught-promise.html:1 Uncaught (in promise) TypeError: Failed to register a ServiceWorker: A bad HTTP response code (404) was received when fetching the script.
 Promise (async)
 promiseTest9 @ console-uncaught-promise.html:93
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
deleted file mode 100644
index a505dce..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
+++ /dev/null
@@ -1,82 +0,0 @@
-  
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true
-    },
-    {
-      "name": "LayoutTextControl TEXTAREA",
-      "position": [18, 18],
-      "bounds": [206, 126],
-      "shouldFlattenTransform": false,
-      "drawsContent": true,
-      "backgroundColor": "#CCCCCC"
-    },
-    {
-      "name": "Scrolling Layer",
-      "position": [1, 1],
-      "bounds": [189, 124],
-      "shouldFlattenTransform": false
-    },
-    {
-      "name": "Scrolling Contents Layer",
-      "bounds": [189, 328],
-      "contentsOpaque": true,
-      "drawsContent": true
-    },
-    {
-      "name": "Overflow Controls Host Layer",
-      "bounds": [206, 126]
-    },
-    {
-      "name": "Vertical Scrollbar Layer",
-      "position": [190, 1],
-      "bounds": [15, 109]
-    },
-    {
-      "name": "Scroll Corner Layer",
-      "position": [190, 110],
-      "bounds": [15, 15],
-      "drawsContent": true
-    },
-    {
-      "name": "LayoutTextControl TEXTAREA",
-      "position": [248, 18],
-      "bounds": [206, 126],
-      "shouldFlattenTransform": false,
-      "drawsContent": true,
-      "backgroundColor": "#CCCCCC"
-    },
-    {
-      "name": "Scrolling Layer",
-      "position": [1, 1],
-      "bounds": [189, 124],
-      "shouldFlattenTransform": false
-    },
-    {
-      "name": "Scrolling Contents Layer",
-      "bounds": [189, 328],
-      "contentsOpaque": true,
-      "drawsContent": true
-    },
-    {
-      "name": "Overflow Controls Host Layer",
-      "bounds": [206, 126]
-    },
-    {
-      "name": "Vertical Scrollbar Layer",
-      "position": [190, 1],
-      "bounds": [15, 109]
-    },
-    {
-      "name": "Scroll Corner Layer",
-      "position": [190, 110],
-      "bounds": [15, 15],
-      "drawsContent": true
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-mime-types.https-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-mime-types.https-expected.txt
new file mode 100644
index 0000000..28bf3a7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-mime-types.https-expected.txt
@@ -0,0 +1,39 @@
+This is a testharness.js-based test.
+FAIL Registering script with no MIME type Test bug: need to pass exception to assert_throws()
+FAIL Registering script with bad MIME type Test bug: need to pass exception to assert_throws()
+FAIL Registering script that imports script with no MIME type assert_unreached: Should have rejected: Registration of no MIME type imported script should fail. Reached unreachable code
+FAIL Registering script that imports script with bad MIME type assert_unreached: Should have rejected: Registration of plain text imported script should fail. Reached unreachable code
+FAIL Registering script with good MIME type application/ecmascript promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type application/ecmascript
+PASS Registering script with good MIME type application/javascript
+PASS Registering script that imports script with good MIME type application/javascript
+FAIL Registering script with good MIME type application/x-ecmascript promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type application/x-ecmascript
+PASS Registering script with good MIME type application/x-javascript
+PASS Registering script that imports script with good MIME type application/x-javascript
+FAIL Registering script with good MIME type text/ecmascript promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/ecmascript
+PASS Registering script with good MIME type text/javascript
+PASS Registering script that imports script with good MIME type text/javascript
+FAIL Registering script with good MIME type text/javascript1.0 promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/javascript1.0
+FAIL Registering script with good MIME type text/javascript1.1 promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/javascript1.1
+FAIL Registering script with good MIME type text/javascript1.2 promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/javascript1.2
+FAIL Registering script with good MIME type text/javascript1.3 promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/javascript1.3
+FAIL Registering script with good MIME type text/javascript1.4 promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/javascript1.4
+FAIL Registering script with good MIME type text/javascript1.5 promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/javascript1.5
+FAIL Registering script with good MIME type text/jscript promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/jscript
+FAIL Registering script with good MIME type text/livescript promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/livescript
+FAIL Registering script with good MIME type text/x-ecmascript promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/x-ecmascript
+FAIL Registering script with good MIME type text/x-javascript promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/x-javascript
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-scope.https-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-scope.https-expected.txt
new file mode 100644
index 0000000..c2ebe84
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-scope.https-expected.txt
@@ -0,0 +1,11 @@
+This is a testharness.js-based test.
+FAIL Scope including URL-encoded slash Test bug: need to pass exception to assert_throws()
+FAIL Scope including URL-encoded backslash Test bug: need to pass exception to assert_throws()
+PASS Scope including URL-encoded multibyte characters
+PASS Scope including non-escaped multibyte characters
+PASS Scope including self-reference
+PASS Scope including parent-reference
+PASS Scope including consecutive slashes
+FAIL Scope URL is same-origin filesystem: URL Test bug: need to pass exception to assert_throws()
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-script-url.https-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-script-url.https-expected.txt
new file mode 100644
index 0000000..ce29087
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-script-url.https-expected.txt
@@ -0,0 +1,9 @@
+This is a testharness.js-based test.
+FAIL Script URL including URL-encoded slash Test bug: need to pass exception to assert_throws()
+FAIL Script URL including uppercase URL-encoded slash Test bug: need to pass exception to assert_throws()
+FAIL Script URL including URL-encoded backslash Test bug: need to pass exception to assert_throws()
+FAIL Script URL including uppercase URL-encoded backslash Test bug: need to pass exception to assert_throws()
+PASS Script URL including self-reference
+PASS Script URL including parent-reference
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-script.https-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-script.https-expected.txt
new file mode 100644
index 0000000..1dbf650
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-script.https-expected.txt
@@ -0,0 +1,12 @@
+This is a testharness.js-based test.
+FAIL Registering invalid chunked encoding script Test bug: need to pass exception to assert_throws()
+FAIL Registering invalid chunked encoding script with flush Test bug: need to pass exception to assert_throws()
+FAIL Registering script including parse error Test bug: need to pass exception to assert_throws()
+FAIL Registering script including undefined error Test bug: need to pass exception to assert_throws()
+FAIL Registering script including uncaught exception Test bug: need to pass exception to assert_throws()
+FAIL Registering script importing malformed script Test bug: need to pass exception to assert_throws()
+FAIL Registering non-existent script Test bug: need to pass exception to assert_throws()
+FAIL Registering script importing non-existent script Test bug: need to pass exception to assert_throws()
+PASS Registering script including caught exception
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-security-error.https-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-security-error.https-expected.txt
new file mode 100644
index 0000000..742add3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-security-error.https-expected.txt
@@ -0,0 +1,11 @@
+This is a testharness.js-based test.
+FAIL Registering same scope as the script directory without the last slashTest bug: need to pass exception to assert_throws()
+FAIL Registration scope outside the script directoryTest bug: need to pass exception to assert_throws()
+FAIL Registering scope outside domainTest bug: need to pass exception to assert_throws()
+FAIL Registering script outside domainTest bug: need to pass exception to assert_throws()
+FAIL Registering redirected scriptTest bug: need to pass exception to assert_throws()
+FAIL Scope including parent-reference and not under the script directoryTest bug: need to pass exception to assert_throws()
+FAIL Script URL including consecutive slashesTest bug: need to pass exception to assert_throws()
+FAIL Script URL is same-origin filesystem: URLTest bug: need to pass exception to assert_throws()
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/registration-mime-types.https-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/registration-mime-types.https-expected.txt
new file mode 100644
index 0000000..e4d2ccd0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/registration-mime-types.https-expected.txt
@@ -0,0 +1,39 @@
+This is a testharness.js-based test.
+PASS Registering script with no MIME type
+PASS Registering script with bad MIME type
+FAIL Registering script that imports script with no MIME type assert_unreached: Should have rejected: Registration of no MIME type imported script should fail. Reached unreachable code
+FAIL Registering script that imports script with bad MIME type assert_unreached: Should have rejected: Registration of plain text imported script should fail. Reached unreachable code
+FAIL Registering script with good MIME type application/ecmascript promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('application/ecmascript')."
+PASS Registering script that imports script with good MIME type application/ecmascript
+PASS Registering script with good MIME type application/javascript
+PASS Registering script that imports script with good MIME type application/javascript
+FAIL Registering script with good MIME type application/x-ecmascript promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('application/x-ecmascript')."
+PASS Registering script that imports script with good MIME type application/x-ecmascript
+PASS Registering script with good MIME type application/x-javascript
+PASS Registering script that imports script with good MIME type application/x-javascript
+FAIL Registering script with good MIME type text/ecmascript promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/ecmascript')."
+PASS Registering script that imports script with good MIME type text/ecmascript
+PASS Registering script with good MIME type text/javascript
+PASS Registering script that imports script with good MIME type text/javascript
+FAIL Registering script with good MIME type text/javascript1.0 promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/javascript1.0')."
+PASS Registering script that imports script with good MIME type text/javascript1.0
+FAIL Registering script with good MIME type text/javascript1.1 promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/javascript1.1')."
+PASS Registering script that imports script with good MIME type text/javascript1.1
+FAIL Registering script with good MIME type text/javascript1.2 promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/javascript1.2')."
+PASS Registering script that imports script with good MIME type text/javascript1.2
+FAIL Registering script with good MIME type text/javascript1.3 promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/javascript1.3')."
+PASS Registering script that imports script with good MIME type text/javascript1.3
+FAIL Registering script with good MIME type text/javascript1.4 promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/javascript1.4')."
+PASS Registering script that imports script with good MIME type text/javascript1.4
+FAIL Registering script with good MIME type text/javascript1.5 promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/javascript1.5')."
+PASS Registering script that imports script with good MIME type text/javascript1.5
+FAIL Registering script with good MIME type text/jscript promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/jscript')."
+PASS Registering script that imports script with good MIME type text/jscript
+FAIL Registering script with good MIME type text/livescript promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/livescript')."
+PASS Registering script that imports script with good MIME type text/livescript
+FAIL Registering script with good MIME type text/x-ecmascript promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/x-ecmascript')."
+PASS Registering script that imports script with good MIME type text/x-ecmascript
+FAIL Registering script with good MIME type text/x-javascript promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/x-javascript')."
+PASS Registering script that imports script with good MIME type text/x-javascript
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/threaded/compositing/visibility/visibility-image-layers-dynamic-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/threaded/compositing/visibility/visibility-image-layers-dynamic-expected.txt
deleted file mode 100644
index a6f5968..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/threaded/compositing/visibility/visibility-image-layers-dynamic-expected.txt
+++ /dev/null
@@ -1,109 +0,0 @@
-
-
-
-Initial
-
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [785, 626],
-      "contentsOpaque": true,
-      "drawsContent": true
-    },
-    {
-      "name": "LayoutBlockFlow DIV class='composited container'",
-      "position": [18, 10],
-      "bounds": [749, 145]
-    },
-    {
-      "name": "LayoutBlockFlow DIV class='composited hidden container'",
-      "position": [14, 316],
-      "bounds": [757, 153],
-      "contentsVisible": false
-    },
-    {
-      "name": "LayoutImage IMG class='visible composited box'",
-      "position": [24, 24],
-      "bounds": [100, 100]
-    }
-  ]
-}
-After step 1
-
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [785, 1062],
-      "contentsOpaque": true,
-      "drawsContent": true
-    },
-    {
-      "name": "LayoutBlockFlow DIV class='composited container'",
-      "position": [18, 10],
-      "bounds": [749, 145]
-    },
-    {
-      "name": "LayoutImage IMG class='hidden composited box'",
-      "position": [20, 20],
-      "bounds": [100, 100]
-    },
-    {
-      "name": "LayoutBlockFlow DIV class='composited hidden container'",
-      "position": [14, 316],
-      "bounds": [757, 153],
-      "contentsVisible": false
-    },
-    {
-      "name": "LayoutImage IMG class='visible composited box'",
-      "position": [24, 24],
-      "bounds": [100, 100]
-    }
-  ]
-}
-After step 2
-
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [785, 1577],
-      "contentsOpaque": true,
-      "drawsContent": true
-    },
-    {
-      "name": "LayoutBlockFlow DIV class='composited container'",
-      "position": [18, 10],
-      "bounds": [749, 145]
-    },
-    {
-      "name": "LayoutImage IMG class='hidden composited box'",
-      "position": [20, 20],
-      "bounds": [100, 100]
-    },
-    {
-      "name": "LayoutBlockFlow DIV class='composited hidden container'",
-      "position": [14, 161],
-      "bounds": [757, 153],
-      "drawsContent": true
-    },
-    {
-      "name": "LayoutImage IMG class='composited box'",
-      "position": [24, 24],
-      "bounds": [100, 100]
-    },
-    {
-      "name": "LayoutBlockFlow DIV class='composited hidden container'",
-      "position": [14, 316],
-      "bounds": [757, 153],
-      "contentsVisible": false
-    },
-    {
-      "name": "LayoutImage IMG class='visible composited box'",
-      "position": [24, 24],
-      "bounds": [100, 100]
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrollbar-layer-placement-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrollbar-layer-placement-expected.txt
index cd12323f..5deec6e26 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrollbar-layer-placement-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrollbar-layer-placement-expected.txt
@@ -14,31 +14,30 @@
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='scroller'",
-      "position": [32, 32],
+      "position": [38, 38],
       "bounds": [278, 218],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#FFFFFF"
     },
     {
       "name": "Scrolling Layer",
-      "position": [29, 29],
-      "bounds": [220, 160],
-      "shouldFlattenTransform": false
+      "position": [67, 67],
+      "bounds": [220, 160]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [67, 67],
       "bounds": [220, 236],
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
-      "position": [24, 24],
+      "position": [62, 62],
       "bounds": [230, 170]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [218, 5],
+      "position": [280, 67],
       "bounds": [7, 160]
     },
     {
@@ -49,26 +48,25 @@
     },
     {
       "name": "LayoutBlockFlow DIV class='scroller'",
-      "position": [32, 32],
+      "position": [387, 38],
       "bounds": [278, 218],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#FFFFFF"
     },
     {
       "name": "Scrolling Layer",
-      "position": [29, 29],
-      "bounds": [220, 160],
-      "shouldFlattenTransform": false
+      "position": [416, 67],
+      "bounds": [220, 160]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [416, 67],
       "bounds": [220, 236],
       "drawsContent": true
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='content'",
-      "position": [73, 73],
+      "position": [428, 79],
       "bounds": [196, 212],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -76,12 +74,12 @@
     },
     {
       "name": "Overflow Controls Host Layer",
-      "position": [56, 56],
+      "position": [411, 62],
       "bounds": [230, 170]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [218, 5],
+      "position": [629, 67],
       "bounds": [7, 160]
     },
     {
@@ -92,32 +90,30 @@
     },
     {
       "name": "Ancestor Clipping Layer",
-      "position": [40, 40],
-      "bounds": [260, 100],
-      "shouldFlattenTransform": false
+      "position": [46, 337],
+      "bounds": [260, 100]
     },
     {
       "name": "LayoutBlockFlow DIV class='scroller'",
-      "position": [-9, -9],
+      "position": [37, 328],
       "bounds": [278, 218],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#FFFFFF"
     },
     {
       "name": "Scrolling Layer",
-      "position": [29, 29],
-      "bounds": [220, 160],
-      "shouldFlattenTransform": false
+      "position": [66, 357],
+      "bounds": [220, 160]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [66, 357],
       "bounds": [220, 236],
       "drawsContent": true
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='content'",
-      "position": [72, 72],
+      "position": [78, 369],
       "bounds": [196, 212],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -125,17 +121,17 @@
     },
     {
       "name": "Overflow Controls Ancestor Clipping Layer",
-      "position": [40, 40],
+      "position": [46, 337],
       "bounds": [260, 100]
     },
     {
       "name": "Overflow Controls Host Layer",
-      "position": [15, 15],
+      "position": [61, 352],
       "bounds": [230, 170]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [218, 5],
+      "position": [279, 357],
       "bounds": [7, 160]
     },
     {
@@ -146,43 +142,41 @@
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='clipper'",
-      "position": [24, 24],
+      "position": [379, 321],
       "bounds": [292, 200],
       "drawsContent": true
     },
     {
       "name": "Child Containment Layer",
-      "position": [10, 10],
+      "position": [389, 331],
       "bounds": [272, 180]
     },
     {
       "name": "Ancestor Clipping Layer",
-      "position": [6, 6],
-      "bounds": [260, 100],
-      "shouldFlattenTransform": false
+      "position": [395, 337],
+      "bounds": [260, 100]
     },
     {
       "name": "LayoutBlockFlow DIV class='scroller'",
-      "position": [-9, -9],
+      "position": [386, 328],
       "bounds": [278, 218],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#FFFFFF"
     },
     {
       "name": "Scrolling Layer",
-      "position": [29, 29],
-      "bounds": [220, 160],
-      "shouldFlattenTransform": false
+      "position": [415, 357],
+      "bounds": [220, 160]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [415, 357],
       "bounds": [220, 236],
       "drawsContent": true
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='content'",
-      "position": [72, 72],
+      "position": [427, 369],
       "bounds": [196, 212],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -190,17 +184,17 @@
     },
     {
       "name": "Overflow Controls Ancestor Clipping Layer",
-      "position": [40, 40],
+      "position": [395, 337],
       "bounds": [260, 100]
     },
     {
       "name": "Overflow Controls Host Layer",
-      "position": [15, 15],
+      "position": [410, 352],
       "bounds": [230, 170]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [218, 5],
+      "position": [628, 357],
       "bounds": [7, 160]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/compositing/overflow/textarea-scroll-touch-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/compositing/overflow/textarea-scroll-touch-expected.txt
index aeb710a5..ee9356d0 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/compositing/overflow/textarea-scroll-touch-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/compositing/overflow/textarea-scroll-touch-expected.txt
@@ -11,34 +11,34 @@
       "name": "LayoutTextControl TEXTAREA",
       "position": [18, 18],
       "bounds": [206, 126],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#CCCCCC"
     },
     {
       "name": "Scrolling Layer",
-      "position": [1, 1],
-      "bounds": [189, 124],
-      "shouldFlattenTransform": false
+      "position": [19, 19],
+      "bounds": [189, 124]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [19, 19],
       "bounds": [189, 308],
       "contentsOpaque": true,
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [18, 18],
       "bounds": [206, 126]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [190, 1],
+      "position": [208, 19],
       "bounds": [15, 109]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [190, 110],
+      "position": [208, 128],
       "bounds": [15, 15],
       "drawsContent": true
     },
@@ -46,34 +46,34 @@
       "name": "LayoutTextControl TEXTAREA",
       "position": [248, 18],
       "bounds": [206, 126],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#CCCCCC"
     },
     {
       "name": "Scrolling Layer",
-      "position": [1, 1],
-      "bounds": [189, 124],
-      "shouldFlattenTransform": false
+      "position": [249, 19],
+      "bounds": [189, 124]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [249, 19],
       "bounds": [189, 308],
       "contentsOpaque": true,
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [248, 18],
       "bounds": [206, 126]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [190, 1],
+      "position": [438, 19],
       "bounds": [15, 109]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [190, 110],
+      "position": [438, 128],
       "bounds": [15, 15],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/external/wpt/uievents/auxclick/auxclick_event-manual-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/external/wpt/uievents/auxclick/auxclick_event-manual-expected.txt
deleted file mode 100644
index d5676bef..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/external/wpt/uievents/auxclick/auxclick_event-manual-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-This is a testharness.js-based test.
-FAIL auxclick event sequence received.assert_equals: detail attribute of auxclick should be the click count. expected 2 but got 1
-PASS PointerEvent Automation
-PASS First auxclick should have detail=1 indicating the fire click
-FAIL Second auxclick should have detail=2 indicating the fire clickassert_equals: detail attribute of auxclick should be the click count. expected 2 but got 1
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
index aeb710a5..ee9356d0 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
@@ -11,34 +11,34 @@
       "name": "LayoutTextControl TEXTAREA",
       "position": [18, 18],
       "bounds": [206, 126],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#CCCCCC"
     },
     {
       "name": "Scrolling Layer",
-      "position": [1, 1],
-      "bounds": [189, 124],
-      "shouldFlattenTransform": false
+      "position": [19, 19],
+      "bounds": [189, 124]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [19, 19],
       "bounds": [189, 308],
       "contentsOpaque": true,
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [18, 18],
       "bounds": [206, 126]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [190, 1],
+      "position": [208, 19],
       "bounds": [15, 109]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [190, 110],
+      "position": [208, 128],
       "bounds": [15, 15],
       "drawsContent": true
     },
@@ -46,34 +46,34 @@
       "name": "LayoutTextControl TEXTAREA",
       "position": [248, 18],
       "bounds": [206, 126],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#CCCCCC"
     },
     {
       "name": "Scrolling Layer",
-      "position": [1, 1],
-      "bounds": [189, 124],
-      "shouldFlattenTransform": false
+      "position": [249, 19],
+      "bounds": [189, 124]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [249, 19],
       "bounds": [189, 308],
       "contentsOpaque": true,
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [248, 18],
       "bounds": [206, 126]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [190, 1],
+      "position": [438, 19],
       "bounds": [15, 109]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [190, 110],
+      "position": [438, 128],
       "bounds": [15, 15],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/compositing/geometry/ancestor-overflow-change-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/compositing/geometry/ancestor-overflow-change-expected.png
deleted file mode 100644
index b48f4127..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-retina/compositing/geometry/ancestor-overflow-change-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/external/wpt/service-workers/service-worker/link-element-register-security-error.https-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-retina/external/wpt/service-workers/service-worker/link-element-register-security-error.https-expected.txt
new file mode 100644
index 0000000..78c5360
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-retina/external/wpt/service-workers/service-worker/link-element-register-security-error.https-expected.txt
@@ -0,0 +1,11 @@
+This is a testharness.js-based test.
+FAIL Registering same scope as the script directory without the last slash Test bug: need to pass exception to assert_throws()
+FAIL Registration scope outside the script directory Test bug: need to pass exception to assert_throws()
+FAIL Registering scope outside domain Test bug: need to pass exception to assert_throws()
+FAIL Registering script outside domain Test bug: need to pass exception to assert_throws()
+FAIL Registering redirected script Test bug: need to pass exception to assert_throws()
+FAIL Scope including parent-reference and not under the script directory Test bug: need to pass exception to assert_throws()
+FAIL Script URL including consecutive slashes Test bug: need to pass exception to assert_throws()
+FAIL Script URL is same-origin filesystem: URL Test bug: need to pass exception to assert_throws()
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/http/tests/devtools/console/console-format-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-retina/http/tests/devtools/console/console-format-expected.txt
new file mode 100644
index 0000000..99da3d48
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-retina/http/tests/devtools/console/console-format-expected.txt
@@ -0,0 +1,816 @@
+CONSOLE MESSAGE: line 27: test,test2,,,test4,,,,,
+CONSOLE MESSAGE: line 28: %o
+CONSOLE MESSAGE: line 29: %O
+CONSOLE MESSAGE: line 30: Test for zero "%f" in formatter
+CONSOLE MESSAGE: line 31: %% self-escape1
+CONSOLE MESSAGE: line 32: %%s self-escape2
+CONSOLE MESSAGE: line 33: %%ss self-escape3
+CONSOLE MESSAGE: line 34: %%s%s%%s self-escape4
+CONSOLE MESSAGE: line 35: %%%%% self-escape5
+CONSOLE MESSAGE: line 36: %%%s self-escape6
+CONSOLE MESSAGE: line 12: /^url\(\s*(?:(?:"(?:[^\\\"]|(?:\\[\da-f]{1,6}\s?|\.))*"|'(?:[^\\\']|(?:\\[\da-f]{1,6}\s?|\.))*')|(?:[!#$%&*-~\w]|(?:\\[\da-f]{1,6}\s?|\.))*)\s*\)/i
+CONSOLE MESSAGE: line 13: /^url\(\s*(?:(?:"(?:[^\\\"]|(?:\\[\da-f]{1,6}\s?|\.))*"|'(?:[^\\\']|(?:\\[\da-f]{1,6}\s?|\.))*')|(?:[!#$%&*-~\w]|(?:\\[\da-f]{1,6}\s?|\.))*)\s*\)/i
+CONSOLE MESSAGE: line 12: /foo\\bar\sbaz/i
+CONSOLE MESSAGE: line 13: /foo\\bar\sbaz/i
+CONSOLE MESSAGE: line 12: test
+CONSOLE MESSAGE: line 13: test
+CONSOLE MESSAGE: line 12: test named "test"
+CONSOLE MESSAGE: line 13: test named "test"
+CONSOLE MESSAGE: line 12: Error
+CONSOLE MESSAGE: line 13: Error
+CONSOLE MESSAGE: line 12: Error: my error message
+CONSOLE MESSAGE: line 13: Error: my error message
+CONSOLE MESSAGE: line 12: Error: my multiline
+error message
+CONSOLE MESSAGE: line 13: Error: my multiline
+error message
+CONSOLE MESSAGE: line 12: [object HTMLParagraphElement]
+CONSOLE MESSAGE: line 13: [object HTMLParagraphElement]
+CONSOLE MESSAGE: line 12: function () { return 1; }
+CONSOLE MESSAGE: line 13: function () { return 1; }
+CONSOLE MESSAGE: line 12: function () {
+        return 2;
+    }
+CONSOLE MESSAGE: line 13: function () {
+        return 2;
+    }
+CONSOLE MESSAGE: line 12: 0.12
+CONSOLE MESSAGE: line 13: 0.12
+CONSOLE MESSAGE: line 12: http://webkit.org/
+CONSOLE MESSAGE: line 13: http://webkit.org/
+CONSOLE MESSAGE: line 12: null
+CONSOLE MESSAGE: line 13: 
+CONSOLE MESSAGE: line 12: undefined
+CONSOLE MESSAGE: line 13: 
+CONSOLE MESSAGE: line 12: [object Attr]
+CONSOLE MESSAGE: line 13: [object Attr]
+CONSOLE MESSAGE: line 12: [object Attr]
+CONSOLE MESSAGE: line 13: [object Attr]
+CONSOLE MESSAGE: line 12: [object Attr]
+CONSOLE MESSAGE: line 13: [object Attr]
+CONSOLE MESSAGE: line 12: [object Object]
+CONSOLE MESSAGE: line 13: [object Object]
+CONSOLE MESSAGE: line 12: NaN
+CONSOLE MESSAGE: line 13: NaN
+CONSOLE MESSAGE: line 12: Infinity
+CONSOLE MESSAGE: line 13: Infinity
+CONSOLE MESSAGE: line 12: -Infinity
+CONSOLE MESSAGE: line 13: -Infinity
+CONSOLE MESSAGE: line 12: test,test2,,,test4,,,,,
+CONSOLE MESSAGE: line 13: test,test2,,,test4,,,,,
+CONSOLE MESSAGE: line 12: [object Object]
+CONSOLE MESSAGE: line 13: [object Object]
+CONSOLE MESSAGE: line 12: function () {}
+CONSOLE MESSAGE: line 13: function () {}
+CONSOLE MESSAGE: line 12: [object Object]
+CONSOLE MESSAGE: line 13: [object Object]
+CONSOLE MESSAGE: line 12: [object SVGSVGElement]
+CONSOLE MESSAGE: line 13: [object SVGSVGElement]
+CONSOLE MESSAGE: line 12: [object Object]
+CONSOLE MESSAGE: line 13: [object Object]
+CONSOLE MESSAGE: line 12: 0
+CONSOLE MESSAGE: line 13: 0
+CONSOLE MESSAGE: line 12: [object Object]
+CONSOLE MESSAGE: line 13: [object Object]
+CONSOLE MESSAGE: line 12: function Object() { [native code] }
+CONSOLE MESSAGE: line 13: function Object() { [native code] }
+CONSOLE MESSAGE: line 12: [object Object]
+CONSOLE MESSAGE: line 13: [object Object]
+CONSOLE MESSAGE: line 12: function ( /**/ foo/**/, /*/**/bar,
+    /**/baz) {}
+CONSOLE MESSAGE: line 13: function ( /**/ foo/**/, /*/**/bar,
+    /**/baz) {}
+CONSOLE MESSAGE: line 12: 42.0000
+CONSOLE MESSAGE: line 13: 42.0000
+CONSOLE MESSAGE: line 12: abc
+CONSOLE MESSAGE: line 13: abc
+CONSOLE MESSAGE: line 12: [object Uint16Array]
+CONSOLE MESSAGE: line 13: [object Uint16Array]
+CONSOLE MESSAGE: line 12: [object Text]
+CONSOLE MESSAGE: line 13: [object Text]
+CONSOLE MESSAGE: line 12: [object DOMException]
+CONSOLE MESSAGE: line 13: [object DOMException]
+CONSOLE MESSAGE: line 12: [object Uint8Array]
+CONSOLE MESSAGE: line 13: [object Uint8Array]
+CONSOLE MESSAGE: line 12: [object Uint8Array]
+CONSOLE MESSAGE: line 13: [object Uint8Array]
+CONSOLE MESSAGE: line 12: [object Uint8Array]
+CONSOLE MESSAGE: line 13: [object Uint8Array]
+CONSOLE MESSAGE: line 12: [object Object]
+CONSOLE MESSAGE: line 13: [object Object]
+CONSOLE MESSAGE: line 12: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
+CONSOLE MESSAGE: line 13: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
+CONSOLE MESSAGE: line 12: test
+CONSOLE MESSAGE: line 13: test
+Tests that console logging dumps proper messages.
+
+ console-format.html:22 Array(10)
+console-format.html:23 Array(10)
+console-format.html:24 Array(10)
+console-format.html:25 Test for zero "0" in formatter
+console-format.html:26 % self-escape1 dummy
+console-format.html:27 %s self-escape2 dummy
+console-format.html:28 %ss self-escape3 dummy
+console-format.html:29 %sdummy%s self-escape4
+console-format.html:30 %%% self-escape5 dummy
+console-format.html:31 %dummy self-escape6
+console-format.html:7 /^url\(\s*(?:(?:"(?:[^\\\"]|(?:\\[\da-f]{1,6}\s?|\.))*"|'(?:[^\\\']|(?:\\[\da-f]{1,6}\s?|\.))*')|(?:[!#$%&*-~\w]|(?:\\[\da-f]{1,6}\s?|\.))*)\s*\)/i
+console-format.html:8 [/^url\(\s*(?:(?:"(?:[^\\\"]|(?:\\[\da-f]{1,6}\s?|\…?:[!#$%&*-~\w]|(?:\\[\da-f]{1,6}\s?|\.))*)\s*\)/i]
+globals[0]
+/^url\(\s*(?:(?:"(?:[^\\\"]|(?:\\[\da-f]{1,6}\s?|\.))*"|'(?:[^\\\']|(?:\\[\da-f]{1,6}\s?|\.))*')|(?:[!#$%&*-~\w]|(?:\\[\da-f]{1,6}\s?|\.))*)\s*\)/i
+console-format.html:7 /foo\\bar\sbaz/i
+console-format.html:8 [/foo\\bar\sbaz/i]
+globals[1]
+/foo\\bar\sbaz/i
+console-format.html:7 test
+console-format.html:8 ["test"]
+globals[2]
+"test"
+console-format.html:7 test named "test"
+console-format.html:8 ["test named "test""]
+globals[3]
+"test named "test""
+console-format.html:7 Error
+console-format.html:8 [Error
+]
+globals[4]
+Error
+console-format.html:7 Error: my error message
+console-format.html:8 [Error: my error message
+]
+globals[5]
+Error: my error message
+console-format.html:7 Error: my multiline
+error message
+console-format.html:8 [Error: my multiline
+error message
+]
+globals[6]
+Error: my multiline
+error message
+console-format.html:7 
+    <p id="p">Tests that console logging dumps proper messages.</p>
+console-format.html:8 [p#p]
+globals[7]
+    <p id="p">Tests that console logging dumps proper messages.</p>
+console-format.html:7 ƒ () { return 1; }
+console-format.html:8 [ƒ]
+globals[8]
+ƒ () { return 1; }
+console-format.html:7 ƒ () {
+        return 2;
+    }
+console-format.html:8 [ƒ]
+globals[9]
+ƒ () {
+        return 2;
+    }
+console-format.html:7 0.12
+console-format.html:8 [0.12]
+globals[10]
+0.12
+console-format.html:7 http://webkit.org/
+console-format.html:8 ["http://webkit.org/"]
+globals[11]
+"http://webkit.org/"
+console-format.html:7 null
+console-format.html:8 [null]
+globals[12]
+null
+console-format.html:7 undefined
+console-format.html:8 [undefined]
+globals[13]
+undefined
+console-format.html:7 
+    attr=""
+console-format.html:8 [attr]
+globals[14]
+    attr=""
+console-format.html:7 
+    attr="value"
+console-format.html:8 [attr]
+globals[15]
+    attr="value"
+console-format.html:7 
+    id="x"
+console-format.html:8 [id]
+globals[16]
+    id="x"
+console-format.html:7 {}
+console-format.html:8 [{…}]
+globals[17]
+{}
+console-format.html:7 NaN
+console-format.html:8 [NaN]
+globals[18]
+NaN
+console-format.html:7 Infinity
+console-format.html:8 [Infinity]
+globals[19]
+Infinity
+console-format.html:7 -Infinity
+console-format.html:8 [-Infinity]
+globals[20]
+-Infinity
+console-format.html:7 (10) ["test", "test2", empty × 2, "test4", empty × 5, foo: {…}]
+console-format.html:8 [Array(10)]
+globals[21]
+(10) ["test", "test2", empty × 2, "test4", empty × 5, foo: {…}]
+console-format.html:7 {}
+console-format.html:8 [{…}]
+globals[22]
+{}
+console-format.html:7 [ƒ]
+console-format.html:8 [Array(1)]
+globals[23]
+[ƒ]
+console-format.html:7 {bar: "bar"}
+console-format.html:8 [{…}]
+globals[24]
+{bar: "bar"}
+console-format.html:7 
+    <svg id="svg-node"></svg>
+console-format.html:8 [svg#svg-node]
+globals[25]
+    <svg id="svg-node"></svg>
+console-format.html:7 {enumerableProp: 4, __underscoreEnumerableProp__: 5, __underscoreNonEnumerableProp: 2, abc: 3, getFoo: ƒ, …}
+console-format.html:8 [{…}]
+globals[26]
+{enumerableProp: 4, __underscoreEnumerableProp__: 5, __underscoreNonEnumerableProp: 2, abc: 3, getFoo: ƒ, …}
+console-format.html:7 -0
+console-format.html:8 [-0]
+globals[27]
+-0
+console-format.html:7 {}
+console-format.html:8 [{…}]
+globals[28]
+{}
+console-format.html:7 ƒ Object() { [native code] }
+console-format.html:8 [ƒ]
+globals[29]
+ƒ Object() { [native code] }
+console-format.html:7 {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
+console-format.html:8 [{…}]
+globals[30]
+{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
+console-format.html:7 ƒ ( /**/ foo/**/, /*/**/bar,
+    /**/baz) {}
+console-format.html:8 [ƒ]
+globals[31]
+ƒ ( /**/ foo/**/, /*/**/bar,
+    /**/baz) {}
+console-format.html:7 Number {[[PrimitiveValue]]: 42}
+console-format.html:8 [Number]
+globals[32]
+Number {[[PrimitiveValue]]: 42}
+console-format.html:7 String {[[PrimitiveValue]]: "abc"}
+console-format.html:8 [String]
+globals[33]
+String {[[PrimitiveValue]]: "abc"}
+console-format.html:7 Uint16Array(3) [1, 2, 3]
+console-format.html:8 [Uint16Array(3)]
+globals[34]
+Uint16Array(3) [1, 2, 3]
+console-format.html:7 #text
+console-format.html:8 [text]
+globals[35]
+#text
+console-format.html:7 DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.
+console-format.html:8 [DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of th…]
+globals[36]
+DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.
+console-format.html:7 Uint8Array [3]
+console-format.html:8 [Uint8Array(1)]
+globals[37]
+Uint8Array [3]
+console-format.html:7 Uint8Array(400) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …]
+console-format.html:8 [Uint8Array(400)]
+globals[38]
+Uint8Array(400) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …]
+console-format.html:7 Uint8Array(400000000) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …]
+console-format.html:8 [Uint8Array(400000000)]
+globals[39]
+Uint8Array(400000000) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …]
+console-format.html:7 namespace.longSubNamespace.x.className {}
+console-format.html:8 [n…e.l…e.x.className]
+globals[40]
+namespace.longSubNamespace.x.className {}
+console-format.html:7 (200) [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …]
+console-format.html:8 [Array(200)]
+globals[41]
+(200) [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …]
+console-format.html:7 ["test"]
+console-format.html:8 [Array(1)]
+globals[42]
+["test"]
+Expanded all messages
+console-format.html:22 Array(10)
+    0: "test"
+    1: "test2"
+    4: "test4"
+    foo: {}
+    length: 10
+    __proto__: Array(0)
+console-format.html:23 Array(10)
+    0: "test"
+    1: "test2"
+    4: "test4"
+    foo: {}
+    length: 10
+    __proto__: Array(0)
+console-format.html:24 Array(10)
+    0: "test"
+    1: "test2"
+    4: "test4"
+    foo: {}
+    length: 10
+    __proto__: Array(0)
+console-format.html:25 Test for zero "0" in formatter
+console-format.html:26 % self-escape1 dummy
+console-format.html:27 %s self-escape2 dummy
+console-format.html:28 %ss self-escape3 dummy
+console-format.html:29 %sdummy%s self-escape4
+console-format.html:30 %%% self-escape5 dummy
+console-format.html:31 %dummy self-escape6
+console-format.html:7 /^url\(\s*(?:(?:"(?:[^\\\"]|(?:\\[\da-f]{1,6}\s?|\.))*"|'(?:[^\\\']|(?:\\[\da-f]{1,6}\s?|\.))*')|(?:[!#$%&*-~\w]|(?:\\[\da-f]{1,6}\s?|\.))*)\s*\)/i
+console-format.html:8 [/^url\(\s*(?:(?:"(?:[^\\\"]|(?:\\[\da-f]{1,6}\s?|\…?:[!#$%&*-~\w]|(?:\\[\da-f]{1,6}\s?|\.))*)\s*\)/i]
+    0: /^url\(\s*(?:(?:"(?:[^\\\"]|(?:\\[\da-f]{1,6}\s?|\.))*"|'(?:[^\\\']|(?:\\[\da-f]{1,6}\s?|\.))*')|(?:[!#$%&*-~\w]|(?:\\[\da-f]{1,6}\s?|\.))*)\s*\)/i
+    length: 1
+    __proto__: Array(0)
+globals[0]
+/^url\(\s*(?:(?:"(?:[^\\\"]|(?:\\[\da-f]{1,6}\s?|\.))*"|'(?:[^\\\']|(?:\\[\da-f]{1,6}\s?|\.))*')|(?:[!#$%&*-~\w]|(?:\\[\da-f]{1,6}\s?|\.))*)\s*\)/i
+console-format.html:7 /foo\\bar\sbaz/i
+console-format.html:8 [/foo\\bar\sbaz/i]
+    0: /foo\\bar\sbaz/i
+    length: 1
+    __proto__: Array(0)
+globals[1]
+/foo\\bar\sbaz/i
+console-format.html:7 test
+console-format.html:8 ["test"]
+    0: "test"
+    length: 1
+    __proto__: Array(0)
+globals[2]
+"test"
+console-format.html:7 test named "test"
+console-format.html:8 ["test named "test""]
+    0: "test named "test""
+    length: 1
+    __proto__: Array(0)
+globals[3]
+"test named "test""
+console-format.html:7 Error
+console-format.html:8 [Error
+]
+    0: Error
+    length: 1
+    __proto__: Array(0)
+globals[4]
+Error
+console-format.html:7 Error: my error message
+console-format.html:8 [Error: my error message
+]
+    0: Error: my error message
+    length: 1
+    __proto__: Array(0)
+globals[5]
+Error: my error message
+console-format.html:7 Error: my multiline
+error message
+console-format.html:8 [Error: my multiline
+error message
+]
+    0: Error: my multiline
+error message
+    length: 1
+    __proto__: Array(0)
+globals[6]
+Error: my multiline
+error message
+console-format.html:7 
+    <p id="p">Tests that console logging dumps proper messages.</p>
+console-format.html:8 [p#p]
+    0: p#p
+    length: 1
+    __proto__: Array(0)
+globals[7]
+    <p id="p">Tests that console logging dumps proper messages.</p>
+console-format.html:7 ƒ () { return 1; }
+console-format.html:8 [ƒ]
+    0: ƒ ()
+    length: 1
+    __proto__: Array(0)
+globals[8]
+ƒ () { return 1; }
+console-format.html:7 ƒ () {
+        return 2;
+    }
+console-format.html:8 [ƒ]
+    0: ƒ ()
+    length: 1
+    __proto__: Array(0)
+globals[9]
+ƒ () {
+        return 2;
+    }
+console-format.html:7 0.12
+console-format.html:8 [0.12]
+    0: 0.12
+    length: 1
+    __proto__: Array(0)
+globals[10]
+0.12
+console-format.html:7 http://webkit.org/
+console-format.html:8 ["http://webkit.org/"]
+    0: "http://webkit.org/"
+    length: 1
+    __proto__: Array(0)
+globals[11]
+"http://webkit.org/"
+console-format.html:7 null
+console-format.html:8 [null]
+    0: null
+    length: 1
+    __proto__: Array(0)
+globals[12]
+null
+console-format.html:7 undefined
+console-format.html:8 [undefined]
+    0: undefined
+    length: 1
+    __proto__: Array(0)
+globals[13]
+undefined
+console-format.html:7 
+    attr=""
+console-format.html:8 [attr]
+    0: attr
+    length: 1
+    __proto__: Array(0)
+globals[14]
+    attr=""
+console-format.html:7 
+    attr="value"
+console-format.html:8 [attr]
+    0: attr
+    length: 1
+    __proto__: Array(0)
+globals[15]
+    attr="value"
+console-format.html:7 
+    id="x"
+console-format.html:8 [id]
+    0: id
+    length: 1
+    __proto__: Array(0)
+globals[16]
+    id="x"
+console-format.html:7 {}
+    length: (...)
+    get length: ƒ length()
+    __proto__: Object
+console-format.html:8 [{…}]
+    0: {}
+    length: 1
+    __proto__: Array(0)
+globals[17]
+{}
+    length: (...)
+    get length: ƒ length()
+    __proto__: Object
+console-format.html:7 NaN
+console-format.html:8 [NaN]
+    0: NaN
+    length: 1
+    __proto__: Array(0)
+globals[18]
+NaN
+console-format.html:7 Infinity
+console-format.html:8 [Infinity]
+    0: Infinity
+    length: 1
+    __proto__: Array(0)
+globals[19]
+Infinity
+console-format.html:7 -Infinity
+console-format.html:8 [-Infinity]
+    0: -Infinity
+    length: 1
+    __proto__: Array(0)
+globals[20]
+-Infinity
+console-format.html:7 (10) ["test", "test2", empty × 2, "test4", empty × 5, foo: {…}]
+    0: "test"
+    1: "test2"
+    4: "test4"
+    foo: {}
+    length: 10
+    __proto__: Array(0)
+console-format.html:8 [Array(10)]
+    0: (10) ["test", "test2", empty × 2, "test4", empty × 5, foo: {…}]
+    length: 1
+    __proto__: Array(0)
+globals[21]
+(10) ["test", "test2", empty × 2, "test4", empty × 5, foo: {…}]
+    0: "test"
+    1: "test2"
+    4: "test4"
+    foo: {}
+    length: 10
+    __proto__: Array(0)
+console-format.html:7 {}
+    __proto__: Object
+console-format.html:8 [{…}]
+    0: {}
+    length: 1
+    __proto__: Array(0)
+globals[22]
+{}
+    __proto__: Object
+console-format.html:7 [ƒ]
+    0: ƒ ()
+    length: 1
+    __proto__: Array(0)
+console-format.html:8 [Array(1)]
+    0: [ƒ]
+    length: 1
+    __proto__: Array(0)
+globals[23]
+[ƒ]
+    0: ƒ ()
+    length: 1
+    __proto__: Array(0)
+console-format.html:7 {bar: "bar"}
+    bar: "bar"
+    __proto__: Object
+console-format.html:8 [{…}]
+    0: {bar: "bar"}
+    length: 1
+    __proto__: Array(0)
+globals[24]
+{bar: "bar"}
+    bar: "bar"
+    __proto__: Object
+console-format.html:7 
+    <svg id="svg-node"></svg>
+console-format.html:8 [svg#svg-node]
+    0: svg#svg-node
+    length: 1
+    __proto__: Array(0)
+globals[25]
+    <svg id="svg-node"></svg>
+console-format.html:7 {enumerableProp: 4, __underscoreEnumerableProp__: 5, __underscoreNonEnumerableProp: 2, abc: 3, getFoo: ƒ, …}
+    enumerableProp: 4
+    __underscoreEnumerableProp__: 5
+    abc: 3
+    bar: (...)
+    getFoo: ƒ ()
+    __underscoreNonEnumerableProp: 2
+    get bar: ƒ ()
+    set bar: ƒ (x)
+    __proto__: Object
+console-format.html:8 [{…}]
+    0: {enumerableProp: 4, __underscoreEnumerableProp__: 5, __underscoreNonEnumerableProp: 2, abc: 3, getFoo: ƒ, …}
+    length: 1
+    __proto__: Array(0)
+globals[26]
+{enumerableProp: 4, __underscoreEnumerableProp__: 5, __underscoreNonEnumerableProp: 2, abc: 3, getFoo: ƒ, …}
+    enumerableProp: 4
+    __underscoreEnumerableProp__: 5
+    abc: 3
+    bar: (...)
+    getFoo: ƒ ()
+    __underscoreNonEnumerableProp: 2
+    get bar: ƒ ()
+    set bar: ƒ (x)
+    __proto__: Object
+console-format.html:7 -0
+console-format.html:8 [-0]
+    0: -0
+    length: 1
+    __proto__: Array(0)
+globals[27]
+-0
+console-format.html:7 {}
+    No properties
+console-format.html:8 [{…}]
+    0: {}
+    length: 1
+    __proto__: Array(0)
+globals[28]
+{}
+    No properties
+console-format.html:7 ƒ Object() { [native code] }
+console-format.html:8 [ƒ]
+    0: ƒ Object()
+    length: 1
+    __proto__: Array(0)
+globals[29]
+ƒ Object() { [native code] }
+console-format.html:7 {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
+    constructor: ƒ Object()
+    hasOwnProperty: ƒ hasOwnProperty()
+    isPrototypeOf: ƒ isPrototypeOf()
+    propertyIsEnumerable: ƒ propertyIsEnumerable()
+    toLocaleString: ƒ toLocaleString()
+    toString: ƒ toString()
+    valueOf: ƒ valueOf()
+    __defineGetter__: ƒ __defineGetter__()
+    __defineSetter__: ƒ __defineSetter__()
+    __lookupGetter__: ƒ __lookupGetter__()
+    __lookupSetter__: ƒ __lookupSetter__()
+    get __proto__: ƒ __proto__()
+    set __proto__: ƒ __proto__()
+console-format.html:8 [{…}]
+    0: {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
+    length: 1
+    __proto__: Array(0)
+globals[30]
+{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
+    constructor: ƒ Object()
+    hasOwnProperty: ƒ hasOwnProperty()
+    isPrototypeOf: ƒ isPrototypeOf()
+    propertyIsEnumerable: ƒ propertyIsEnumerable()
+    toLocaleString: ƒ toLocaleString()
+    toString: ƒ toString()
+    valueOf: ƒ valueOf()
+    __defineGetter__: ƒ __defineGetter__()
+    __defineSetter__: ƒ __defineSetter__()
+    __lookupGetter__: ƒ __lookupGetter__()
+    __lookupSetter__: ƒ __lookupSetter__()
+    get __proto__: ƒ __proto__()
+    set __proto__: ƒ __proto__()
+console-format.html:7 ƒ ( /**/ foo/**/, /*/**/bar,
+    /**/baz) {}
+console-format.html:8 [ƒ]
+    0: ƒ ( /**/ foo/**/, /*/**/bar,     /**/baz)
+    length: 1
+    __proto__: Array(0)
+globals[31]
+ƒ ( /**/ foo/**/, /*/**/bar,
+    /**/baz) {}
+console-format.html:7 Number {[[PrimitiveValue]]: 42}
+    __proto__: Number
+    [[PrimitiveValue]]: 42
+console-format.html:8 [Number]
+    0: Number {[[PrimitiveValue]]: 42}
+    length: 1
+    __proto__: Array(0)
+globals[32]
+Number {[[PrimitiveValue]]: 42}
+    __proto__: Number
+    [[PrimitiveValue]]: 42
+console-format.html:7 String {[[PrimitiveValue]]: "abc"}
+    0: "a"
+    1: "b"
+    2: "c"
+    length: 3
+    __proto__: String
+    [[PrimitiveValue]]: "abc"
+console-format.html:8 [String]
+    0: String {[[PrimitiveValue]]: "abc"}
+    length: 1
+    __proto__: Array(0)
+globals[33]
+String {[[PrimitiveValue]]: "abc"}
+    0: "a"
+    1: "b"
+    2: "c"
+    length: 3
+    __proto__: String
+    [[PrimitiveValue]]: "abc"
+console-format.html:7 Uint16Array(3) [1, 2, 3]
+    0: 1
+    1: 2
+    2: 3
+    buffer: (...)
+    byteLength: (...)
+    byteOffset: (...)
+    length: (...)
+    Symbol(Symbol.toStringTag): (...)
+    __proto__: TypedArray
+console-format.html:8 [Uint16Array(3)]
+    0: Uint16Array(3) [1, 2, 3]
+    length: 1
+    __proto__: Array(0)
+globals[34]
+Uint16Array(3) [1, 2, 3]
+    0: 1
+    1: 2
+    2: 3
+    buffer: (...)
+    byteLength: (...)
+    byteOffset: (...)
+    length: (...)
+    Symbol(Symbol.toStringTag): (...)
+    __proto__: TypedArray
+console-format.html:7 #text
+console-format.html:8 [text]
+    0: text
+    length: 1
+    __proto__: Array(0)
+globals[35]
+#text
+console-format.html:7 DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.
+console-format.html:8 [DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of th…]
+    0: DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.
+    length: 1
+    __proto__: Array(0)
+globals[36]
+DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.
+console-format.html:7 Uint8Array [3]
+    0: 3
+    buffer: (...)
+    byteLength: (...)
+    byteOffset: (...)
+    length: (...)
+    Symbol(Symbol.toStringTag): (...)
+    __proto__: TypedArray
+console-format.html:8 [Uint8Array(1)]
+    0: Uint8Array [3]
+    length: 1
+    __proto__: Array(0)
+globals[37]
+Uint8Array [3]
+    0: 3
+    buffer: (...)
+    byteLength: (...)
+    byteOffset: (...)
+    length: (...)
+    Symbol(Symbol.toStringTag): (...)
+    __proto__: TypedArray
+console-format.html:7 Uint8Array(400) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …]
+    [0 … 99]
+    [100 … 199]
+    [200 … 299]
+    [300 … 399]
+    foo: "bar"
+    __proto__: TypedArray
+console-format.html:8 [Uint8Array(400)]
+    0: Uint8Array(400) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …]
+    length: 1
+    __proto__: Array(0)
+globals[38]
+Uint8Array(400) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …]
+    [0 … 99]
+    [100 … 199]
+    [200 … 299]
+    [300 … 399]
+    foo: "bar"
+    __proto__: TypedArray
+console-format.html:7 Uint8Array(400000000) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …]
+    [0 … 99999999]
+    [100000000 … 199999999]
+    [200000000 … 299999999]
+    [300000000 … 399999999]
+    __proto__: TypedArray
+console-format.html:8 [Uint8Array(400000000)]
+    0: Uint8Array(400000000) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …]
+    length: 1
+    __proto__: Array(0)
+globals[39]
+Uint8Array(400000000) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …]
+    [0 … 99999999]
+    [100000000 … 199999999]
+    [200000000 … 299999999]
+    [300000000 … 399999999]
+    __proto__: TypedArray
+console-format.html:7 namespace.longSubNamespace.x.className {}
+    __proto__: Object
+console-format.html:8 [n…e.l…e.x.className]
+    0: namespace.longSubNamespace.x.className {}
+    length: 1
+    __proto__: Array(0)
+globals[40]
+namespace.longSubNamespace.x.className {}
+    __proto__: Object
+console-format.html:7 (200) [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …]
+    [0 … 99]
+    [100 … 199]
+    length: 200
+    __proto__: Array(0)
+console-format.html:8 [Array(200)]
+    0: (200) [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …]
+    length: 1
+    __proto__: Array(0)
+globals[41]
+(200) [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …]
+    [0 … 99]
+    [100 … 199]
+    length: 200
+    __proto__: Array(0)
+console-format.html:7 ["test"]
+    0: "test"
+    length: 1
+    __proto__: Array(0)
+console-format.html:8 [Array(1)]
+    0: ["test"]
+    length: 1
+    __proto__: Array(0)
+globals[42]
+["test"]
+    0: "test"
+    length: 1
+    __proto__: Array(0)
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-security-error.https-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-security-error.https-expected.txt
new file mode 100644
index 0000000..78c5360
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-security-error.https-expected.txt
@@ -0,0 +1,11 @@
+This is a testharness.js-based test.
+FAIL Registering same scope as the script directory without the last slash Test bug: need to pass exception to assert_throws()
+FAIL Registration scope outside the script directory Test bug: need to pass exception to assert_throws()
+FAIL Registering scope outside domain Test bug: need to pass exception to assert_throws()
+FAIL Registering script outside domain Test bug: need to pass exception to assert_throws()
+FAIL Registering redirected script Test bug: need to pass exception to assert_throws()
+FAIL Scope including parent-reference and not under the script directory Test bug: need to pass exception to assert_throws()
+FAIL Script URL including consecutive slashes Test bug: need to pass exception to assert_throws()
+FAIL Script URL is same-origin filesystem: URL Test bug: need to pass exception to assert_throws()
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrollbar-layer-placement-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrollbar-layer-placement-expected.txt
index cd12323f..5deec6e26 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrollbar-layer-placement-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrollbar-layer-placement-expected.txt
@@ -14,31 +14,30 @@
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='scroller'",
-      "position": [32, 32],
+      "position": [38, 38],
       "bounds": [278, 218],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#FFFFFF"
     },
     {
       "name": "Scrolling Layer",
-      "position": [29, 29],
-      "bounds": [220, 160],
-      "shouldFlattenTransform": false
+      "position": [67, 67],
+      "bounds": [220, 160]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [67, 67],
       "bounds": [220, 236],
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
-      "position": [24, 24],
+      "position": [62, 62],
       "bounds": [230, 170]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [218, 5],
+      "position": [280, 67],
       "bounds": [7, 160]
     },
     {
@@ -49,26 +48,25 @@
     },
     {
       "name": "LayoutBlockFlow DIV class='scroller'",
-      "position": [32, 32],
+      "position": [387, 38],
       "bounds": [278, 218],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#FFFFFF"
     },
     {
       "name": "Scrolling Layer",
-      "position": [29, 29],
-      "bounds": [220, 160],
-      "shouldFlattenTransform": false
+      "position": [416, 67],
+      "bounds": [220, 160]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [416, 67],
       "bounds": [220, 236],
       "drawsContent": true
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='content'",
-      "position": [73, 73],
+      "position": [428, 79],
       "bounds": [196, 212],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -76,12 +74,12 @@
     },
     {
       "name": "Overflow Controls Host Layer",
-      "position": [56, 56],
+      "position": [411, 62],
       "bounds": [230, 170]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [218, 5],
+      "position": [629, 67],
       "bounds": [7, 160]
     },
     {
@@ -92,32 +90,30 @@
     },
     {
       "name": "Ancestor Clipping Layer",
-      "position": [40, 40],
-      "bounds": [260, 100],
-      "shouldFlattenTransform": false
+      "position": [46, 337],
+      "bounds": [260, 100]
     },
     {
       "name": "LayoutBlockFlow DIV class='scroller'",
-      "position": [-9, -9],
+      "position": [37, 328],
       "bounds": [278, 218],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#FFFFFF"
     },
     {
       "name": "Scrolling Layer",
-      "position": [29, 29],
-      "bounds": [220, 160],
-      "shouldFlattenTransform": false
+      "position": [66, 357],
+      "bounds": [220, 160]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [66, 357],
       "bounds": [220, 236],
       "drawsContent": true
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='content'",
-      "position": [72, 72],
+      "position": [78, 369],
       "bounds": [196, 212],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -125,17 +121,17 @@
     },
     {
       "name": "Overflow Controls Ancestor Clipping Layer",
-      "position": [40, 40],
+      "position": [46, 337],
       "bounds": [260, 100]
     },
     {
       "name": "Overflow Controls Host Layer",
-      "position": [15, 15],
+      "position": [61, 352],
       "bounds": [230, 170]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [218, 5],
+      "position": [279, 357],
       "bounds": [7, 160]
     },
     {
@@ -146,43 +142,41 @@
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='clipper'",
-      "position": [24, 24],
+      "position": [379, 321],
       "bounds": [292, 200],
       "drawsContent": true
     },
     {
       "name": "Child Containment Layer",
-      "position": [10, 10],
+      "position": [389, 331],
       "bounds": [272, 180]
     },
     {
       "name": "Ancestor Clipping Layer",
-      "position": [6, 6],
-      "bounds": [260, 100],
-      "shouldFlattenTransform": false
+      "position": [395, 337],
+      "bounds": [260, 100]
     },
     {
       "name": "LayoutBlockFlow DIV class='scroller'",
-      "position": [-9, -9],
+      "position": [386, 328],
       "bounds": [278, 218],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#FFFFFF"
     },
     {
       "name": "Scrolling Layer",
-      "position": [29, 29],
-      "bounds": [220, 160],
-      "shouldFlattenTransform": false
+      "position": [415, 357],
+      "bounds": [220, 160]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [415, 357],
       "bounds": [220, 236],
       "drawsContent": true
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='content'",
-      "position": [72, 72],
+      "position": [427, 369],
       "bounds": [196, 212],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -190,17 +184,17 @@
     },
     {
       "name": "Overflow Controls Ancestor Clipping Layer",
-      "position": [40, 40],
+      "position": [395, 337],
       "bounds": [260, 100]
     },
     {
       "name": "Overflow Controls Host Layer",
-      "position": [15, 15],
+      "position": [410, 352],
       "bounds": [230, 170]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [218, 5],
+      "position": [628, 357],
       "bounds": [7, 160]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-security-error.https-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-security-error.https-expected.txt
new file mode 100644
index 0000000..78c5360
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-security-error.https-expected.txt
@@ -0,0 +1,11 @@
+This is a testharness.js-based test.
+FAIL Registering same scope as the script directory without the last slash Test bug: need to pass exception to assert_throws()
+FAIL Registration scope outside the script directory Test bug: need to pass exception to assert_throws()
+FAIL Registering scope outside domain Test bug: need to pass exception to assert_throws()
+FAIL Registering script outside domain Test bug: need to pass exception to assert_throws()
+FAIL Registering redirected script Test bug: need to pass exception to assert_throws()
+FAIL Scope including parent-reference and not under the script directory Test bug: need to pass exception to assert_throws()
+FAIL Script URL including consecutive slashes Test bug: need to pass exception to assert_throws()
+FAIL Script URL is same-origin filesystem: URL Test bug: need to pass exception to assert_throws()
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/compositing/geometry/bounds-ignores-hidden-composited-descendant-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/bounds-ignores-hidden-composited-descendant-expected.txt
similarity index 87%
rename from third_party/WebKit/LayoutTests/compositing/geometry/bounds-ignores-hidden-composited-descendant-expected.txt
rename to third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/bounds-ignores-hidden-composited-descendant-expected.txt
index 8f49ed1..6d52403 100644
--- a/third_party/WebKit/LayoutTests/compositing/geometry/bounds-ignores-hidden-composited-descendant-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/bounds-ignores-hidden-composited-descendant-expected.txt
@@ -11,20 +11,18 @@
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited'",
       "position": [10, 10],
-      "transformOrigin": [-10, -10],
       "bounds": [590, 208],
       "drawsContent": true
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited'",
       "position": [10, 260],
-      "transformOrigin": [-10, -10],
       "bounds": [590, 208],
       "drawsContent": true
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='composited inner box'",
-      "position": [490, 108],
+      "position": [500, 368],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "drawsContent": true,
diff --git a/third_party/WebKit/LayoutTests/compositing/geometry/composited-in-columns-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/composited-in-columns-expected.txt
similarity index 93%
rename from third_party/WebKit/LayoutTests/compositing/geometry/composited-in-columns-expected.txt
rename to third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/composited-in-columns-expected.txt
index 2adaf03..fd5a5fd9 100644
--- a/third_party/WebKit/LayoutTests/compositing/geometry/composited-in-columns-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/composited-in-columns-expected.txt
@@ -15,7 +15,7 @@
     },
     {
       "name": "LayoutBlockFlow DIV class='composited box'",
-      "position": [5, 5],
+      "position": [19, 167],
       "bounds": [50, 50],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -30,7 +30,7 @@
     },
     {
       "name": "LayoutBlockFlow DIV class='composited box'",
-      "position": [5, 5],
+      "position": [277, 93],
       "bounds": [50, 50],
       "contentsOpaque": true,
       "drawsContent": true,
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/layer-due-to-layer-children-deep-switch-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/layer-due-to-layer-children-deep-switch-expected.txt
index 729faa7..f4730214 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/layer-due-to-layer-children-deep-switch-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/layer-due-to-layer-children-deep-switch-expected.txt
@@ -30,7 +30,7 @@
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='child'",
-      "position": [31, 39],
+      "position": [39, 47],
       "bounds": [250, 220],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -43,12 +43,7 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#FFFF00",
-      "transform": [
-        [0.866025403784439, 0.5, 0, 0],
-        [-0.5, 0.866025403784439, 0, 0],
-        [0, 0, 1, 0],
-        [0, 0, 0, 1]
-      ]
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='greatgrandchild'",
@@ -57,12 +52,30 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#008000",
+      "transform": 2
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [0.866025403784439, 0.5, 0, 0],
+        [-0.5, 0.866025403784439, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, 0, 1]
+      ],
+      "origin": [100, 100]
+    },
+    {
+      "id": 2,
+      "parent": 1,
       "transform": [
         [0.5, 0, -0.866025403784439, 0.0021650635094611],
         [0, 1, 0, 0],
         [0.866025403784439, 0, 0.5, -0.00125],
         [-30, 30, 100, 0.75]
-      ]
+      ],
+      "origin": [125, 50]
     }
   ]
 }
@@ -72,7 +85,7 @@
   "layers": [
     {
       "name": "LayoutView #document",
-      "bounds": [785, 1316],
+      "bounds": [785, 1511],
       "contentsOpaque": true,
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/layer-due-to-layer-children-switch-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/layer-due-to-layer-children-switch-expected.txt
index 6eb54dc..1e29c24 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/layer-due-to-layer-children-switch-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/layer-due-to-layer-children-switch-expected.txt
@@ -35,12 +35,19 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#008000",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
       "transform": [
         [0.707106781186548, 0, -0.707106781186548, 0.00117851130197758],
         [0, 1, 0, 0],
         [0.707106781186548, 0, 0.707106781186548, -0.00117851130197758],
         [-50, 10, 100, 0.833333333333333]
-      ]
+      ],
+      "origin": [125, 50]
     }
   ]
 }
@@ -50,7 +57,7 @@
   "layers": [
     {
       "name": "LayoutView #document",
-      "bounds": [785, 886],
+      "bounds": [785, 991],
       "contentsOpaque": true,
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/limit-layer-bounds-overflow-root-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/limit-layer-bounds-overflow-root-expected.txt
index bedcb84a..d19ec2c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/limit-layer-bounds-overflow-root-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/limit-layer-bounds-overflow-root-expected.txt
@@ -7,8 +7,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='compositing'",
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/preserve-3d-switching-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/preserve-3d-switching-expected.txt
index e527aaf8..15fdf45 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/preserve-3d-switching-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/preserve-3d-switching-expected.txt
@@ -18,29 +18,16 @@
     {
       "name": "Child Transform Layer",
       "bounds": [304, 304],
-      "shouldFlattenTransform": false,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, -0.002],
-        [0, 0, 0, 1]
-      ]
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow DIV id='parent'",
       "position": [12, 12],
       "bounds": [280, 280],
       "contentsOpaque": true,
-      "shouldFlattenTransform": false,
-      "3dRenderingContext": 1,
       "drawsContent": true,
       "backgroundColor": "#FFFF00",
-      "transform": [
-        [0.766044443118978, -0.556670399226419, -0.32139380484327, 0],
-        [0, 0.5, -0.866025403784439, 0],
-        [0.642787609686539, 0.663413948168938, 0.383022221559489, 0],
-        [0, 0, 0, 1]
-      ]
+      "transform": 2
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV",
@@ -48,15 +35,47 @@
       "bounds": [200, 200],
       "opacity": 0.699999988079071,
       "contentsOpaque": true,
-      "3dRenderingContext": 1,
       "drawsContent": true,
       "backgroundColor": "#008000",
+      "transform": 3
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, -0.002],
+        [0, 0, 0, 1]
+      ],
+      "origin": [152, 152],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [0.766044443118978, -0.556670399226419, -0.32139380484327, 0],
+        [0, 0.5, -0.866025403784439, 0],
+        [0.642787609686539, 0.663413948168938, 0.383022221559489, 0],
+        [0, 0, 0, 1]
+      ],
+      "origin": [140, 140],
+      "flattenInheritedTransform": false,
+      "renderingContext": 1
+    },
+    {
+      "id": 3,
+      "parent": 2,
       "transform": [
         [0.766044443118978, 0, 0.642787609686539, 0],
         [0, 1, 0, 0],
         [-0.642787609686539, 0, 0.766044443118978, 0],
         [0, 0, 50, 1]
-      ]
+      ],
+      "origin": [100, 100],
+      "renderingContext": 1
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/invisible-nested-iframe-show-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/compositing/iframes/invisible-nested-iframe-show-expected.txt
similarity index 77%
rename from third_party/WebKit/LayoutTests/compositing/iframes/invisible-nested-iframe-show-expected.txt
rename to third_party/WebKit/LayoutTests/platform/mac/compositing/iframes/invisible-nested-iframe-show-expected.txt
index e83143a2..d8ccdaa9 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/invisible-nested-iframe-show-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/iframes/invisible-nested-iframe-show-expected.txt
@@ -15,56 +15,64 @@
     },
     {
       "name": "Frame Overflow Controls Host Layer",
-      "position": [34, 34],
+      "position": [23, 23],
       "bounds": [300, 150]
     },
     {
       "name": "Frame Clipping Layer",
+      "position": [23, 23],
       "bounds": [285, 150]
     },
     {
-      "name": "Frame Scrolling Layer"
+      "name": "Frame Scrolling Layer",
+      "position": [23, 23]
     },
     {
       "name": "Content Root Layer",
+      "position": [23, 23],
       "bounds": [285, 192]
     },
     {
       "name": "LayoutView #document",
+      "position": [23, 23],
       "bounds": [285, 192],
       "drawsContent": true
     },
     {
       "name": "LayoutIFrame IFRAME",
-      "position": [8, 8],
+      "position": [31, 31],
       "bounds": [252, 172],
       "drawsContent": true
     },
     {
       "name": "Frame Overflow Controls Host Layer",
-      "position": [1, 1],
+      "position": [32, 32],
       "bounds": [250, 170]
     },
     {
       "name": "Frame Clipping Layer",
+      "position": [32, 32],
       "bounds": [250, 170]
     },
     {
-      "name": "Frame Scrolling Layer"
+      "name": "Frame Scrolling Layer",
+      "position": [32, 32]
     },
     {
       "name": "Content Root Layer",
+      "position": [32, 32],
       "bounds": [250, 230]
     },
     {
       "name": "LayoutView #document",
+      "position": [32, 32],
       "bounds": [250, 230],
       "drawsContent": true,
       "backgroundColor": "#C0C0C0"
     },
     {
       "name": "LayoutBlockFlow DIV id='iframe-content' class='box'",
-      "position": [18, 10],
+      "position": [50, 42],
       "bounds": [210, 210],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -72,7 +80,7 @@
     },
     {
       "name": "Frame Vertical Scrollbar Layer",
-      "position": [285, 0],
+      "position": [308, 23],
       "bounds": [15, 150]
     },
     {
@@ -82,6 +90,12 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#0000FF",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-nonscrollable-body-mismatch-containers-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/compositing/layer-creation/fixed-position-nonscrollable-body-mismatch-containers-expected.txt
similarity index 84%
rename from third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-nonscrollable-body-mismatch-containers-expected.txt
rename to third_party/WebKit/LayoutTests/platform/mac/compositing/layer-creation/fixed-position-nonscrollable-body-mismatch-containers-expected.txt
index e039efd..0f853e7 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-nonscrollable-body-mismatch-containers-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/layer-creation/fixed-position-nonscrollable-body-mismatch-containers-expected.txt
@@ -12,37 +12,37 @@
       "name": "LayoutBlockFlow DIV class='scrollable bigBox'",
       "position": [8, 68],
       "bounds": [302, 302],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "position": [1, 1],
-      "bounds": [285, 285],
-      "shouldFlattenTransform": false
+      "position": [9, 69],
+      "bounds": [285, 285]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [9, 69],
       "bounds": [285, 800],
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 68],
       "bounds": [302, 302]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [1, 286],
+      "position": [9, 354],
       "bounds": [285, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [286, 1],
+      "position": [294, 69],
       "bounds": [15, 285]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [286, 286],
+      "position": [294, 354],
       "bounds": [15, 15],
       "drawsContent": true
     },
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/layer-creation/no-compositing-for-preserve-3d-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/compositing/layer-creation/no-compositing-for-preserve-3d-expected.txt
index a7067f23..de1d798 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/layer-creation/no-compositing-for-preserve-3d-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/layer-creation/no-compositing-for-preserve-3d-expected.txt
@@ -13,24 +13,36 @@
       "name": "LayoutBlockFlow DIV class='preserve3d'",
       "position": [18, 390],
       "bounds": [342, 180],
-      "shouldFlattenTransform": false,
-      "3dRenderingContext": 1,
-      "drawsContent": true
+      "drawsContent": true,
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='box'",
       "position": [31, 49],
       "bounds": [100, 100],
       "contentsOpaque": true,
-      "3dRenderingContext": 1,
       "drawsContent": true,
       "backgroundColor": "#C0C0C0",
+      "transform": 2
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "flattenInheritedTransform": false,
+      "renderingContext": 1
+    },
+    {
+      "id": 2,
+      "parent": 1,
       "transform": [
         [0.984807753012208, 0, -0.17364817766693, 0],
         [0, 1, 0, 0],
         [0.17364817766693, 0, 0.984807753012208, 0],
         [0, 0, 0, 1]
-      ]
+      ],
+      "origin": [50, 50],
+      "renderingContext": 1
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/textarea-scroll-touch-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/textarea-scroll-touch-expected.txt
index f61e47ca..c535ae7 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/textarea-scroll-touch-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/textarea-scroll-touch-expected.txt
@@ -11,34 +11,34 @@
       "name": "LayoutTextControl TEXTAREA",
       "position": [18, 18],
       "bounds": [206, 126],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#CCCCCC"
     },
     {
       "name": "Scrolling Layer",
-      "position": [1, 1],
-      "bounds": [189, 124],
-      "shouldFlattenTransform": false
+      "position": [19, 19],
+      "bounds": [189, 124]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [19, 19],
       "bounds": [189, 270],
       "contentsOpaque": true,
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [18, 18],
       "bounds": [206, 126]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [190, 1],
+      "position": [208, 19],
       "bounds": [15, 109]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [190, 110],
+      "position": [208, 128],
       "bounds": [15, 15],
       "drawsContent": true
     },
@@ -46,34 +46,34 @@
       "name": "LayoutTextControl TEXTAREA",
       "position": [248, 18],
       "bounds": [206, 126],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#CCCCCC"
     },
     {
       "name": "Scrolling Layer",
-      "position": [1, 1],
-      "bounds": [189, 124],
-      "shouldFlattenTransform": false
+      "position": [249, 19],
+      "bounds": [189, 124]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [249, 19],
       "bounds": [189, 270],
       "contentsOpaque": true,
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [248, 18],
       "bounds": [206, 126]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [190, 1],
+      "position": [438, 19],
       "bounds": [15, 109]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [190, 110],
+      "position": [438, 128],
       "bounds": [15, 15],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/squashing/no-squashing-into-another-clip-layer-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/compositing/squashing/no-squashing-into-another-clip-layer-expected.txt
index 20efe5c..d46d695 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/squashing/no-squashing-into-another-clip-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/squashing/no-squashing-into-another-clip-layer-expected.txt
@@ -16,10 +16,12 @@
     },
     {
       "name": "Child Containment Layer",
+      "position": [8, 8],
       "bounds": [784, 10]
     },
     {
       "name": "LayoutBlockFlow DIV id='inner'",
+      "position": [8, 8],
       "bounds": [784, 10],
       "contentsOpaque": true,
       "drawsContent": true,
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/squashing/selection-repaint-with-gaps-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/compositing/squashing/selection-repaint-with-gaps-expected.txt
index 9d822583..042a31fb 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/squashing/selection-repaint-with-gaps-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/squashing/selection-repaint-with-gaps-expected.txt
@@ -8,8 +8,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow DIV class='overlap'",
@@ -62,8 +61,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow DIV class='overlap'",
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/video/video-poster-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/compositing/video/video-poster-expected.txt
index 6a0434d..3f4dd11a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/video/video-poster-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/video/video-poster-expected.txt
@@ -42,8 +42,7 @@
       "bounds": [352, 288]
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutFlexibleBox (relative positioned) DIV",
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/visibility/visibility-image-layers-dynamic-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/compositing/visibility/visibility-image-layers-dynamic-expected.txt
index 790ed1b..22c5698 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/visibility/visibility-image-layers-dynamic-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/visibility/visibility-image-layers-dynamic-expected.txt
@@ -24,7 +24,7 @@
     },
     {
       "name": "LayoutImage IMG class='visible composited box'",
-      "position": [24, 24],
+      "position": [38, 338],
       "bounds": [100, 100]
     }
   ]
@@ -46,7 +46,7 @@
     },
     {
       "name": "LayoutImage IMG class='hidden composited box'",
-      "position": [20, 20],
+      "position": [38, 30],
       "bounds": [100, 100]
     },
     {
@@ -57,7 +57,7 @@
     },
     {
       "name": "LayoutImage IMG class='visible composited box'",
-      "position": [24, 24],
+      "position": [38, 338],
       "bounds": [100, 100]
     }
   ]
@@ -79,7 +79,7 @@
     },
     {
       "name": "LayoutImage IMG class='hidden composited box'",
-      "position": [20, 20],
+      "position": [38, 30],
       "bounds": [100, 100]
     },
     {
@@ -90,7 +90,7 @@
     },
     {
       "name": "LayoutImage IMG class='composited box'",
-      "position": [24, 24],
+      "position": [38, 184],
       "bounds": [100, 100]
     },
     {
@@ -101,7 +101,7 @@
     },
     {
       "name": "LayoutImage IMG class='visible composited box'",
-      "position": [24, 24],
+      "position": [38, 338],
       "bounds": [100, 100]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/mix-blend-mode-composited-layers-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/css3/blending/mix-blend-mode-composited-layers-expected.txt
index e64624f..e8a2b58d 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/mix-blend-mode-composited-layers-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/css3/blending/mix-blend-mode-composited-layers-expected.txt
@@ -21,6 +21,7 @@
     },
     {
       "name": "LayoutBlockFlow DIV",
+      "position": [8, 18],
       "bounds": [10, 10],
       "contentsOpaque": true,
       "drawsContent": true,
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css3/filters/composited-layer-child-bounds-after-composited-to-sw-shadow-change-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/css3/filters/composited-layer-child-bounds-after-composited-to-sw-shadow-change-expected.txt
index ab44f76..caf6a420 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/css3/filters/composited-layer-child-bounds-after-composited-to-sw-shadow-change-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/css3/filters/composited-layer-child-bounds-after-composited-to-sw-shadow-change-expected.txt
@@ -16,6 +16,7 @@
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='absolutely-positioned-composited-child'",
+      "position": [100, 100],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -41,6 +42,7 @@
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='absolutely-positioned-composited-child'",
+      "position": [100, 100],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "drawsContent": true,
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/canvas-composite-repaint-by-all-imagesource-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/canvas-composite-repaint-by-all-imagesource-expected.txt
similarity index 99%
rename from third_party/WebKit/LayoutTests/paint/invalidation/canvas-composite-repaint-by-all-imagesource-expected.txt
rename to third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/canvas-composite-repaint-by-all-imagesource-expected.txt
index bbe89d1ef..b1ec30ba 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/canvas-composite-repaint-by-all-imagesource-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/canvas-composite-repaint-by-all-imagesource-expected.txt
@@ -235,8 +235,7 @@
       "bounds": [150, 60]
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutFlexibleBox (relative positioned) DIV",
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-with-composited-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-with-composited-scroll-expected.txt
index 69ee0c96f..467d14c0 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-with-composited-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-with-composited-scroll-expected.txt
@@ -10,16 +10,16 @@
       "name": "LayoutBlockFlow DIV id='scroller'",
       "position": [8, 44],
       "bounds": [100, 100],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [100, 100],
-      "shouldFlattenTransform": false
+      "position": [8, 44],
+      "bounds": [100, 100]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 44],
       "bounds": [205, 1019],
       "drawsContent": true,
       "paintInvalidations": [
@@ -37,17 +37,18 @@
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 44],
       "bounds": [100, 100]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [0, 100],
+      "position": [8, 144],
       "bounds": [100, 0],
       "drawsContent": true
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [100, 0],
+      "position": [108, 44],
       "bounds": [0, 100],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/composited-table-row-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/composited-table-row-expected.txt
index bb881861..7fa8981 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/composited-table-row-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/composited-table-row-expected.txt
@@ -9,7 +9,6 @@
     {
       "name": "LayoutTableRow TR",
       "position": [8, 8],
-      "transformOrigin": [37.5, 10.5],
       "bounds": [76, 22],
       "drawsContent": true,
       "backgroundColor": "#FF0000",
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt
index fedc58e0..658821ef 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt
@@ -7,8 +7,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow DIV id='foo'",
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/compositing/remove-squashed-layer-plus-move-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/compositing/remove-squashed-layer-plus-move-expected.txt
index 3ed5b0bd..d9d43ab 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/compositing/remove-squashed-layer-plus-move-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/compositing/remove-squashed-layer-plus-move-expected.txt
@@ -24,8 +24,7 @@
       ]
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV",
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/offset-change-wrong-invalidation-with-float-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/offset-change-wrong-invalidation-with-float-expected.txt
index 53c16ff..9cccbd0a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/offset-change-wrong-invalidation-with-float-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/offset-change-wrong-invalidation-with-float-expected.txt
@@ -31,13 +31,12 @@
     {
       "name": "LayoutListItem (floating) LI id='watches'",
       "position": [31, 42],
-      "transformOrigin": [17, 9],
       "bounds": [24, 18],
       "drawsContent": true
     },
     {
       "name": "LayoutInline (relative positioned) SPAN id='placeholder'",
-      "position": [17, 0],
+      "position": [48, 42],
       "backfaceVisibility": "hidden"
     },
     {
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/overflow-scroll-local-background-text-color-change-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/overflow-scroll-local-background-text-color-change-expected.txt
similarity index 91%
rename from third_party/WebKit/LayoutTests/paint/invalidation/overflow-scroll-local-background-text-color-change-expected.txt
rename to third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/overflow-scroll-local-background-text-color-change-expected.txt
index f69c707..995a6c5 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/overflow-scroll-local-background-text-color-change-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/overflow-scroll-local-background-text-color-change-expected.txt
@@ -10,7 +10,6 @@
       "name": "LayoutBlockFlow DIV id='scroller'",
       "position": [8, 8],
       "bounds": [200, 200],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#0000FF",
       "paintInvalidations": [
@@ -23,11 +22,12 @@
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [185, 185],
-      "shouldFlattenTransform": false
+      "position": [8, 8],
+      "bounds": [185, 185]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 8],
       "bounds": [185, 550],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -41,11 +41,12 @@
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 8],
       "bounds": [200, 200]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [0, 185],
+      "position": [8, 193],
       "bounds": [185, 15],
       "paintInvalidations": [
         {
@@ -57,7 +58,7 @@
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [185, 0],
+      "position": [193, 8],
       "bounds": [15, 185],
       "paintInvalidations": [
         {
@@ -74,7 +75,7 @@
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [185, 185],
+      "position": [193, 193],
       "bounds": [15, 15],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/selection/selection-within-composited-scroller-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/selection/selection-within-composited-scroller-expected.txt
index 7feda9d8..d388d5ed 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/selection/selection-within-composited-scroller-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/selection/selection-within-composited-scroller-expected.txt
@@ -10,17 +10,17 @@
       "name": "LayoutBlockFlow DIV id='scroller'",
       "position": [8, 8],
       "bounds": [200, 200],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#D3D3D3"
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [185, 185],
-      "shouldFlattenTransform": false
+      "position": [8, 8],
+      "bounds": [185, 185]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 8],
       "bounds": [200, 1620],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -34,21 +34,22 @@
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 8],
       "bounds": [200, 200]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [0, 185],
+      "position": [8, 193],
       "bounds": [185, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [185, 0],
+      "position": [193, 8],
       "bounds": [15, 185]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [185, 185],
+      "position": [193, 193],
       "bounds": [15, 15],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/transform-focus-ring-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/transform-focus-ring-repaint-expected.txt
index 240879d..2cc23ef0 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/transform-focus-ring-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/transform-focus-ring-repaint-expected.txt
@@ -29,16 +29,22 @@
     {
       "name": "LayoutBlockFlow (positioned) DIV",
       "position": [108, 158],
-      "transformOrigin": [150, 150],
       "bounds": [440, 300],
       "drawsContent": true,
       "backgroundColor": "#0000FF",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
       "transform": [
         [0, 1, 0, 0],
         [-1, 0, 0, 0],
         [0, 0, 1, 0],
         [0, 0, 0, 1]
-      ]
+      ],
+      "origin": [150, 150]
     }
   ],
   "objectPaintInvalidations": [
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/table/composited-table-background-composited-row-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/table/composited-table-background-composited-row-expected.txt
index e7a75d7..71e5ac4 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/table/composited-table-background-composited-row-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/table/composited-table-background-composited-row-expected.txt
@@ -22,7 +22,7 @@
     },
     {
       "name": "LayoutTableCell TD",
-      "position": [64, 0],
+      "position": [72, 94],
       "bounds": [59, 64],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/table/composited-table-background-composited-row-initial-empty-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/table/composited-table-background-composited-row-initial-empty-expected.txt
index e7a75d7..71e5ac4 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/table/composited-table-background-composited-row-initial-empty-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/table/composited-table-background-composited-row-initial-empty-expected.txt
@@ -22,7 +22,7 @@
     },
     {
       "name": "LayoutTableCell TD",
-      "position": [64, 0],
+      "position": [72, 94],
       "bounds": [59, 64],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/table/composited-table-background-section-composited-row-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/table/composited-table-background-section-composited-row-expected.txt
index d1f8357..36ce6de 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/table/composited-table-background-section-composited-row-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/table/composited-table-background-section-composited-row-expected.txt
@@ -22,13 +22,13 @@
     },
     {
       "name": "LayoutTableRow TR",
-      "position": [0, 68],
+      "position": [8, 94],
       "bounds": [186, 64],
       "drawsContent": true
     },
     {
       "name": "LayoutTableCell TD",
-      "position": [64, 0],
+      "position": [72, 94],
       "bounds": [59, 64],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/table/composited-table-background-section-composited-row-initial-empty-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/table/composited-table-background-section-composited-row-initial-empty-expected.txt
index d1f8357..36ce6de 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/table/composited-table-background-section-composited-row-initial-empty-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/table/composited-table-background-section-composited-row-initial-empty-expected.txt
@@ -22,13 +22,13 @@
     },
     {
       "name": "LayoutTableRow TR",
-      "position": [0, 68],
+      "position": [8, 94],
       "bounds": [186, 64],
       "drawsContent": true
     },
     {
       "name": "LayoutTableCell TD",
-      "position": [64, 0],
+      "position": [72, 94],
       "bounds": [59, 64],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/table/composited-table-background-section-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/table/composited-table-background-section-expected.txt
index 307c2ce0..2c8d298 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/table/composited-table-background-section-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/table/composited-table-background-section-expected.txt
@@ -22,7 +22,7 @@
     },
     {
       "name": "LayoutTableCell TD",
-      "position": [64, 68],
+      "position": [72, 94],
       "bounds": [59, 64],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/table/composited-table-background-section-initial-empty-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/table/composited-table-background-section-initial-empty-expected.txt
index 307c2ce0..2c8d298 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/table/composited-table-background-section-initial-empty-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/table/composited-table-background-section-initial-empty-expected.txt
@@ -22,7 +22,7 @@
     },
     {
       "name": "LayoutTableCell TD",
-      "position": [64, 68],
+      "position": [72, 94],
       "bounds": [59, 64],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/video-mute-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/video-mute-repaint-expected.txt
index 2bb6c5f8..3a644241 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/video-mute-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/video-mute-repaint-expected.txt
@@ -19,8 +19,7 @@
       "bounds": [700, 525]
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutFlexibleBox (relative positioned) DIV",
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/video-unmute-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/video-unmute-repaint-expected.txt
index 7b358d1..99e846d 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/video-unmute-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/video-unmute-repaint-expected.txt
@@ -19,8 +19,7 @@
       "bounds": [700, 525]
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutFlexibleBox (relative positioned) DIV",
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/markers/suggestion-marker-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac/paint/markers/suggestion-marker-basic-expected.png
new file mode 100644
index 0000000..47ec1b0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/markers/suggestion-marker-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/markers/suggestion-marker-basic-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/markers/suggestion-marker-basic-expected.txt
new file mode 100644
index 0000000..8d644ef
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/markers/suggestion-marker-basic-expected.txt
@@ -0,0 +1,102 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x418
+  LayoutBlockFlow {HTML} at (0,0) size 800x418
+    LayoutBlockFlow {BODY} at (8,8) size 784x0
+      LayoutBlockFlow (floating) {DIV} at (582.25,0) size 201.75x176
+        LayoutBlockFlow {P} at (0,16) size 201.75x18
+          LayoutText {#text} at (172,0) size 30x18
+            text run at (172,0) width 30: "RTL"
+        LayoutBlockFlow {DIV} at (0,50) size 201.75x18
+          LayoutText {#text} at (128,0) size 74x18
+            text run at (128,0) width 74: "markRtlAll"
+        LayoutBlockFlow {DIV} at (0,68) size 201.75x18
+          LayoutText {#text} at (91,0) size 111x18
+            text run at (91,0) width 111: "markRtlAllThick"
+        LayoutBlockFlow {DIV} at (0,86) size 201.75x18
+          LayoutText {#text} at (82,0) size 120x18
+            text run at (82,0) width 120: "markRtlBeginning"
+        LayoutBlockFlow {DIV} at (0,104) size 201.75x18
+          LayoutText {#text} at (0,0) size 202x18
+            text run at (0,0) width 202: "markRtlAllExceptFirstAndLast"
+        LayoutBlockFlow {DIV} at (0,122) size 201.75x18
+          LayoutText {#text} at (123,0) size 79x18
+            text run at (123,0) width 79: "markRtlEnd"
+        LayoutBlockFlow {DIV} at (0,140) size 201.75x36
+          LayoutBlockFlow {DIV} at (0,0) size 201.75x18
+            LayoutText {#text} at (149,0) size 34x18
+              text run at (149,0) width 34: "mark"
+            LayoutInline {SPAN} at (0,0) size 20x18
+              LayoutText {#text} at (182,0) size 20x18
+                text run at (182,0) width 20: "Rtl"
+          LayoutBlockFlow {DIV} at (0,18) size 201.75x18
+            LayoutText {#text} at (116,0) size 86x18
+              text run at (116,0) width 86: "AcrossNodes"
+      LayoutBlockFlow (floating) {DIV} at (0,0) size 338.61x410
+        LayoutBlockFlow {P} at (0,16) size 338.61x18
+          LayoutText {#text} at (0,0) size 29x18
+            text run at (0,0) width 29: "LTR"
+        LayoutBlockFlow {DIV} at (0,50) size 338.61x18
+          LayoutText {#text} at (0,0) size 54x18
+            text run at (0,0) width 54: "markAll"
+        LayoutBlockFlow {DIV} at (0,68) size 338.61x18
+          LayoutText {#text} at (0,0) size 91x18
+            text run at (0,0) width 91: "markAllThick"
+        LayoutBlockFlow {DIV} at (0,86) size 338.61x18
+          LayoutText {#text} at (0,0) size 155x18
+            text run at (0,0) width 155: "markAllDifferentColors"
+        LayoutBlockFlow {DIV} at (0,104) size 338.61x18
+          LayoutText {#text} at (0,0) size 100x18
+            text run at (0,0) width 100: "markBeginning"
+        LayoutBlockFlow {DIV} at (0,122) size 338.61x18
+          LayoutText {#text} at (0,0) size 183x18
+            text run at (0,0) width 183: "markAllExceptFirstAndLast"
+        LayoutBlockFlow {DIV} at (0,140) size 338.61x18
+          LayoutText {#text} at (0,0) size 59x18
+            text run at (0,0) width 59: "markEnd"
+        LayoutBlockFlow {DIV} at (0,158) size 338.61x18
+          LayoutText {#text} at (0,0) size 116x18
+            text run at (0,0) width 116: "markNothingZero"
+        LayoutBlockFlow {DIV} at (0,176) size 338.61x18
+          LayoutText {#text} at (0,0) size 112x18
+            text run at (0,0) width 112: "markNothingEnd"
+        LayoutBlockFlow {DIV} at (0,194) size 338.61x36
+          LayoutBlockFlow {DIV} at (0,0) size 338.61x18
+            LayoutText {#text} at (0,0) size 33x18
+              text run at (0,0) width 33: "mark"
+            LayoutInline {SPAN} at (0,0) size 46x18
+              LayoutText {#text} at (32,0) size 46x18
+                text run at (32,0) width 46: "Across"
+          LayoutBlockFlow {DIV} at (0,18) size 338.61x18
+            LayoutText {#text} at (0,0) size 41x18
+              text run at (0,0) width 41: "Nodes"
+        LayoutBlockFlow {DIV} at (0,230) size 338.61x18
+          LayoutText {#text} at (0,0) size 250x18
+            text run at (0,0) width 250: "overridingSpellingMarkerAtBeginning"
+        LayoutBlockFlow {DIV} at (0,248) size 338.61x18
+          LayoutText {#text} at (0,0) size 209x18
+            text run at (0,0) width 209: "overridingSpellingMarkerAtEnd"
+        LayoutBlockFlow {DIV} at (0,266) size 338.61x18
+          LayoutText {#text} at (0,0) size 310x18
+            text run at (0,0) width 310: "overridingSpellingMarkerIntersectingBeginning"
+        LayoutBlockFlow {DIV} at (0,284) size 338.61x18
+          LayoutText {#text} at (0,0) size 269x18
+            text run at (0,0) width 269: "overridingSpellingMarkerIntersectingEnd"
+        LayoutBlockFlow {DIV} at (0,302) size 338.61x18
+          LayoutText {#text} at (0,0) size 258x18
+            text run at (0,0) width 258: "notOverridingSpellingMarkersTouching"
+        LayoutBlockFlow {DIV} at (0,320) size 338.61x18
+          LayoutText {#text} at (0,0) size 280x18
+            text run at (0,0) width 280: "overridingCompositionMarkerAtBeginning"
+        LayoutBlockFlow {DIV} at (0,338) size 338.61x18
+          LayoutText {#text} at (0,0) size 239x18
+            text run at (0,0) width 239: "overridingCompositionMarkerAtEnd"
+        LayoutBlockFlow {DIV} at (0,356) size 338.61x18
+          LayoutText {#text} at (0,0) size 339x18
+            text run at (0,0) width 339: "overridingCompositionMarkerIntersectingBeginning"
+        LayoutBlockFlow {DIV} at (0,374) size 338.61x18
+          LayoutText {#text} at (0,0) size 298x18
+            text run at (0,0) width 298: "overridingCompositionMarkerIntersectingEnd"
+        LayoutBlockFlow {DIV} at (0,392) size 338.61x18
+          LayoutText {#text} at (0,0) size 287x18
+            text run at (0,0) width 287: "notOverridingCompositionMarkersTouching"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/ancestor-overflow-change-expected.png b/third_party/WebKit/LayoutTests/platform/mac/paint/markers/suggestion-marker-split-expected.png
similarity index 65%
rename from third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/ancestor-overflow-change-expected.png
rename to third_party/WebKit/LayoutTests/platform/mac/paint/markers/suggestion-marker-split-expected.png
index ce77def2..212c6dbd 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/ancestor-overflow-change-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/markers/suggestion-marker-split-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/markers/suggestion-marker-split-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/markers/suggestion-marker-split-expected.txt
new file mode 100644
index 0000000..1b29cefc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/markers/suggestion-marker-split-expected.txt
@@ -0,0 +1,20 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x52
+  LayoutBlockFlow {HTML} at (0,0) size 800x52
+    LayoutBlockFlow {BODY} at (8,8) size 784x36
+      LayoutBlockFlow {DIV} at (0,0) size 784x18
+        LayoutText {#text} at (0,0) size 23x18
+          text run at (0,0) width 23: "abc"
+        LayoutText {#text} at (22,0) size 33x18
+          text run at (22,0) width 33: " xxx "
+        LayoutText {#text} at (54,0) size 21x18
+          text run at (54,0) width 21: "def"
+layer at (8,26) size 128x18 scrollWidth 163
+  LayoutBlockFlow {DIV} at (0,18) size 128x18
+    LayoutText {#text} at (0,0) size 64x18
+      text run at (0,0) width 64: "abcdefghi"
+    LayoutText {#text} at (63,0) size 33x18
+      text run at (63,0) width 33: " xxx "
+    LayoutText {#text} at (95,0) size 67x18
+      text run at (95,0) width 67: "jklmnopqr"
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-mime-types.https-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-mime-types.https-expected.txt
new file mode 100644
index 0000000..28bf3a7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-mime-types.https-expected.txt
@@ -0,0 +1,39 @@
+This is a testharness.js-based test.
+FAIL Registering script with no MIME type Test bug: need to pass exception to assert_throws()
+FAIL Registering script with bad MIME type Test bug: need to pass exception to assert_throws()
+FAIL Registering script that imports script with no MIME type assert_unreached: Should have rejected: Registration of no MIME type imported script should fail. Reached unreachable code
+FAIL Registering script that imports script with bad MIME type assert_unreached: Should have rejected: Registration of plain text imported script should fail. Reached unreachable code
+FAIL Registering script with good MIME type application/ecmascript promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type application/ecmascript
+PASS Registering script with good MIME type application/javascript
+PASS Registering script that imports script with good MIME type application/javascript
+FAIL Registering script with good MIME type application/x-ecmascript promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type application/x-ecmascript
+PASS Registering script with good MIME type application/x-javascript
+PASS Registering script that imports script with good MIME type application/x-javascript
+FAIL Registering script with good MIME type text/ecmascript promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/ecmascript
+PASS Registering script with good MIME type text/javascript
+PASS Registering script that imports script with good MIME type text/javascript
+FAIL Registering script with good MIME type text/javascript1.0 promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/javascript1.0
+FAIL Registering script with good MIME type text/javascript1.1 promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/javascript1.1
+FAIL Registering script with good MIME type text/javascript1.2 promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/javascript1.2
+FAIL Registering script with good MIME type text/javascript1.3 promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/javascript1.3
+FAIL Registering script with good MIME type text/javascript1.4 promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/javascript1.4
+FAIL Registering script with good MIME type text/javascript1.5 promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/javascript1.5
+FAIL Registering script with good MIME type text/jscript promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/jscript
+FAIL Registering script with good MIME type text/livescript promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/livescript
+FAIL Registering script with good MIME type text/x-ecmascript promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/x-ecmascript
+FAIL Registering script with good MIME type text/x-javascript promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/x-javascript
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-scope.https-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-scope.https-expected.txt
new file mode 100644
index 0000000..c2ebe84
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-scope.https-expected.txt
@@ -0,0 +1,11 @@
+This is a testharness.js-based test.
+FAIL Scope including URL-encoded slash Test bug: need to pass exception to assert_throws()
+FAIL Scope including URL-encoded backslash Test bug: need to pass exception to assert_throws()
+PASS Scope including URL-encoded multibyte characters
+PASS Scope including non-escaped multibyte characters
+PASS Scope including self-reference
+PASS Scope including parent-reference
+PASS Scope including consecutive slashes
+FAIL Scope URL is same-origin filesystem: URL Test bug: need to pass exception to assert_throws()
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-script-url.https-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-script-url.https-expected.txt
new file mode 100644
index 0000000..ce29087
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-script-url.https-expected.txt
@@ -0,0 +1,9 @@
+This is a testharness.js-based test.
+FAIL Script URL including URL-encoded slash Test bug: need to pass exception to assert_throws()
+FAIL Script URL including uppercase URL-encoded slash Test bug: need to pass exception to assert_throws()
+FAIL Script URL including URL-encoded backslash Test bug: need to pass exception to assert_throws()
+FAIL Script URL including uppercase URL-encoded backslash Test bug: need to pass exception to assert_throws()
+PASS Script URL including self-reference
+PASS Script URL including parent-reference
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-script.https-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-script.https-expected.txt
new file mode 100644
index 0000000..1dbf650
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-script.https-expected.txt
@@ -0,0 +1,12 @@
+This is a testharness.js-based test.
+FAIL Registering invalid chunked encoding script Test bug: need to pass exception to assert_throws()
+FAIL Registering invalid chunked encoding script with flush Test bug: need to pass exception to assert_throws()
+FAIL Registering script including parse error Test bug: need to pass exception to assert_throws()
+FAIL Registering script including undefined error Test bug: need to pass exception to assert_throws()
+FAIL Registering script including uncaught exception Test bug: need to pass exception to assert_throws()
+FAIL Registering script importing malformed script Test bug: need to pass exception to assert_throws()
+FAIL Registering non-existent script Test bug: need to pass exception to assert_throws()
+FAIL Registering script importing non-existent script Test bug: need to pass exception to assert_throws()
+PASS Registering script including caught exception
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-security-error.https-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-security-error.https-expected.txt
new file mode 100644
index 0000000..742add3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/mojo-blobs/external/wpt/service-workers/service-worker/link-element-register-security-error.https-expected.txt
@@ -0,0 +1,11 @@
+This is a testharness.js-based test.
+FAIL Registering same scope as the script directory without the last slashTest bug: need to pass exception to assert_throws()
+FAIL Registration scope outside the script directoryTest bug: need to pass exception to assert_throws()
+FAIL Registering scope outside domainTest bug: need to pass exception to assert_throws()
+FAIL Registering script outside domainTest bug: need to pass exception to assert_throws()
+FAIL Registering redirected scriptTest bug: need to pass exception to assert_throws()
+FAIL Scope including parent-reference and not under the script directoryTest bug: need to pass exception to assert_throws()
+FAIL Script URL including consecutive slashesTest bug: need to pass exception to assert_throws()
+FAIL Script URL is same-origin filesystem: URLTest bug: need to pass exception to assert_throws()
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/mojo-blobs/external/wpt/service-workers/service-worker/registration-mime-types.https-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/mojo-blobs/external/wpt/service-workers/service-worker/registration-mime-types.https-expected.txt
new file mode 100644
index 0000000..e4d2ccd0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/mojo-blobs/external/wpt/service-workers/service-worker/registration-mime-types.https-expected.txt
@@ -0,0 +1,39 @@
+This is a testharness.js-based test.
+PASS Registering script with no MIME type
+PASS Registering script with bad MIME type
+FAIL Registering script that imports script with no MIME type assert_unreached: Should have rejected: Registration of no MIME type imported script should fail. Reached unreachable code
+FAIL Registering script that imports script with bad MIME type assert_unreached: Should have rejected: Registration of plain text imported script should fail. Reached unreachable code
+FAIL Registering script with good MIME type application/ecmascript promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('application/ecmascript')."
+PASS Registering script that imports script with good MIME type application/ecmascript
+PASS Registering script with good MIME type application/javascript
+PASS Registering script that imports script with good MIME type application/javascript
+FAIL Registering script with good MIME type application/x-ecmascript promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('application/x-ecmascript')."
+PASS Registering script that imports script with good MIME type application/x-ecmascript
+PASS Registering script with good MIME type application/x-javascript
+PASS Registering script that imports script with good MIME type application/x-javascript
+FAIL Registering script with good MIME type text/ecmascript promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/ecmascript')."
+PASS Registering script that imports script with good MIME type text/ecmascript
+PASS Registering script with good MIME type text/javascript
+PASS Registering script that imports script with good MIME type text/javascript
+FAIL Registering script with good MIME type text/javascript1.0 promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/javascript1.0')."
+PASS Registering script that imports script with good MIME type text/javascript1.0
+FAIL Registering script with good MIME type text/javascript1.1 promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/javascript1.1')."
+PASS Registering script that imports script with good MIME type text/javascript1.1
+FAIL Registering script with good MIME type text/javascript1.2 promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/javascript1.2')."
+PASS Registering script that imports script with good MIME type text/javascript1.2
+FAIL Registering script with good MIME type text/javascript1.3 promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/javascript1.3')."
+PASS Registering script that imports script with good MIME type text/javascript1.3
+FAIL Registering script with good MIME type text/javascript1.4 promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/javascript1.4')."
+PASS Registering script that imports script with good MIME type text/javascript1.4
+FAIL Registering script with good MIME type text/javascript1.5 promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/javascript1.5')."
+PASS Registering script that imports script with good MIME type text/javascript1.5
+FAIL Registering script with good MIME type text/jscript promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/jscript')."
+PASS Registering script that imports script with good MIME type text/jscript
+FAIL Registering script with good MIME type text/livescript promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/livescript')."
+PASS Registering script that imports script with good MIME type text/livescript
+FAIL Registering script with good MIME type text/x-ecmascript promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/x-ecmascript')."
+PASS Registering script that imports script with good MIME type text/x-ecmascript
+FAIL Registering script with good MIME type text/x-javascript promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/x-javascript')."
+PASS Registering script that imports script with good MIME type text/x-javascript
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
index f61e47ca..c535ae7 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
@@ -11,34 +11,34 @@
       "name": "LayoutTextControl TEXTAREA",
       "position": [18, 18],
       "bounds": [206, 126],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#CCCCCC"
     },
     {
       "name": "Scrolling Layer",
-      "position": [1, 1],
-      "bounds": [189, 124],
-      "shouldFlattenTransform": false
+      "position": [19, 19],
+      "bounds": [189, 124]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [19, 19],
       "bounds": [189, 270],
       "contentsOpaque": true,
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [18, 18],
       "bounds": [206, 126]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [190, 1],
+      "position": [208, 19],
       "bounds": [15, 109]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [190, 110],
+      "position": [208, 128],
       "bounds": [15, 15],
       "drawsContent": true
     },
@@ -46,34 +46,34 @@
       "name": "LayoutTextControl TEXTAREA",
       "position": [248, 18],
       "bounds": [206, 126],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#CCCCCC"
     },
     {
       "name": "Scrolling Layer",
-      "position": [1, 1],
-      "bounds": [189, 124],
-      "shouldFlattenTransform": false
+      "position": [249, 19],
+      "bounds": [189, 124]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [249, 19],
       "bounds": [189, 270],
       "contentsOpaque": true,
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [248, 18],
       "bounds": [206, 126]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [190, 1],
+      "position": [438, 19],
       "bounds": [15, 109]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [190, 110],
+      "position": [438, 128],
       "bounds": [15, 15],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-mime-types.https-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-mime-types.https-expected.txt
new file mode 100644
index 0000000..28bf3a7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-mime-types.https-expected.txt
@@ -0,0 +1,39 @@
+This is a testharness.js-based test.
+FAIL Registering script with no MIME type Test bug: need to pass exception to assert_throws()
+FAIL Registering script with bad MIME type Test bug: need to pass exception to assert_throws()
+FAIL Registering script that imports script with no MIME type assert_unreached: Should have rejected: Registration of no MIME type imported script should fail. Reached unreachable code
+FAIL Registering script that imports script with bad MIME type assert_unreached: Should have rejected: Registration of plain text imported script should fail. Reached unreachable code
+FAIL Registering script with good MIME type application/ecmascript promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type application/ecmascript
+PASS Registering script with good MIME type application/javascript
+PASS Registering script that imports script with good MIME type application/javascript
+FAIL Registering script with good MIME type application/x-ecmascript promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type application/x-ecmascript
+PASS Registering script with good MIME type application/x-javascript
+PASS Registering script that imports script with good MIME type application/x-javascript
+FAIL Registering script with good MIME type text/ecmascript promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/ecmascript
+PASS Registering script with good MIME type text/javascript
+PASS Registering script that imports script with good MIME type text/javascript
+FAIL Registering script with good MIME type text/javascript1.0 promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/javascript1.0
+FAIL Registering script with good MIME type text/javascript1.1 promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/javascript1.1
+FAIL Registering script with good MIME type text/javascript1.2 promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/javascript1.2
+FAIL Registering script with good MIME type text/javascript1.3 promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/javascript1.3
+FAIL Registering script with good MIME type text/javascript1.4 promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/javascript1.4
+FAIL Registering script with good MIME type text/javascript1.5 promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/javascript1.5
+FAIL Registering script with good MIME type text/jscript promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/jscript
+FAIL Registering script with good MIME type text/livescript promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/livescript
+FAIL Registering script with good MIME type text/x-ecmascript promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/x-ecmascript
+FAIL Registering script with good MIME type text/x-javascript promise_test: Unhandled rejection with value: object "[object Event]"
+PASS Registering script that imports script with good MIME type text/x-javascript
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-scope.https-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-scope.https-expected.txt
new file mode 100644
index 0000000..c2ebe84
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-scope.https-expected.txt
@@ -0,0 +1,11 @@
+This is a testharness.js-based test.
+FAIL Scope including URL-encoded slash Test bug: need to pass exception to assert_throws()
+FAIL Scope including URL-encoded backslash Test bug: need to pass exception to assert_throws()
+PASS Scope including URL-encoded multibyte characters
+PASS Scope including non-escaped multibyte characters
+PASS Scope including self-reference
+PASS Scope including parent-reference
+PASS Scope including consecutive slashes
+FAIL Scope URL is same-origin filesystem: URL Test bug: need to pass exception to assert_throws()
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-script-url.https-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-script-url.https-expected.txt
new file mode 100644
index 0000000..ce29087
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-script-url.https-expected.txt
@@ -0,0 +1,9 @@
+This is a testharness.js-based test.
+FAIL Script URL including URL-encoded slash Test bug: need to pass exception to assert_throws()
+FAIL Script URL including uppercase URL-encoded slash Test bug: need to pass exception to assert_throws()
+FAIL Script URL including URL-encoded backslash Test bug: need to pass exception to assert_throws()
+FAIL Script URL including uppercase URL-encoded backslash Test bug: need to pass exception to assert_throws()
+PASS Script URL including self-reference
+PASS Script URL including parent-reference
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-script.https-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-script.https-expected.txt
new file mode 100644
index 0000000..1dbf650
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-script.https-expected.txt
@@ -0,0 +1,12 @@
+This is a testharness.js-based test.
+FAIL Registering invalid chunked encoding script Test bug: need to pass exception to assert_throws()
+FAIL Registering invalid chunked encoding script with flush Test bug: need to pass exception to assert_throws()
+FAIL Registering script including parse error Test bug: need to pass exception to assert_throws()
+FAIL Registering script including undefined error Test bug: need to pass exception to assert_throws()
+FAIL Registering script including uncaught exception Test bug: need to pass exception to assert_throws()
+FAIL Registering script importing malformed script Test bug: need to pass exception to assert_throws()
+FAIL Registering non-existent script Test bug: need to pass exception to assert_throws()
+FAIL Registering script importing non-existent script Test bug: need to pass exception to assert_throws()
+PASS Registering script including caught exception
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-security-error.https-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-security-error.https-expected.txt
new file mode 100644
index 0000000..742add3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/link-element-register-security-error.https-expected.txt
@@ -0,0 +1,11 @@
+This is a testharness.js-based test.
+FAIL Registering same scope as the script directory without the last slashTest bug: need to pass exception to assert_throws()
+FAIL Registration scope outside the script directoryTest bug: need to pass exception to assert_throws()
+FAIL Registering scope outside domainTest bug: need to pass exception to assert_throws()
+FAIL Registering script outside domainTest bug: need to pass exception to assert_throws()
+FAIL Registering redirected scriptTest bug: need to pass exception to assert_throws()
+FAIL Scope including parent-reference and not under the script directoryTest bug: need to pass exception to assert_throws()
+FAIL Script URL including consecutive slashesTest bug: need to pass exception to assert_throws()
+FAIL Script URL is same-origin filesystem: URLTest bug: need to pass exception to assert_throws()
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/registration-mime-types.https-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/registration-mime-types.https-expected.txt
new file mode 100644
index 0000000..e4d2ccd0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/registration-mime-types.https-expected.txt
@@ -0,0 +1,39 @@
+This is a testharness.js-based test.
+PASS Registering script with no MIME type
+PASS Registering script with bad MIME type
+FAIL Registering script that imports script with no MIME type assert_unreached: Should have rejected: Registration of no MIME type imported script should fail. Reached unreachable code
+FAIL Registering script that imports script with bad MIME type assert_unreached: Should have rejected: Registration of plain text imported script should fail. Reached unreachable code
+FAIL Registering script with good MIME type application/ecmascript promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('application/ecmascript')."
+PASS Registering script that imports script with good MIME type application/ecmascript
+PASS Registering script with good MIME type application/javascript
+PASS Registering script that imports script with good MIME type application/javascript
+FAIL Registering script with good MIME type application/x-ecmascript promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('application/x-ecmascript')."
+PASS Registering script that imports script with good MIME type application/x-ecmascript
+PASS Registering script with good MIME type application/x-javascript
+PASS Registering script that imports script with good MIME type application/x-javascript
+FAIL Registering script with good MIME type text/ecmascript promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/ecmascript')."
+PASS Registering script that imports script with good MIME type text/ecmascript
+PASS Registering script with good MIME type text/javascript
+PASS Registering script that imports script with good MIME type text/javascript
+FAIL Registering script with good MIME type text/javascript1.0 promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/javascript1.0')."
+PASS Registering script that imports script with good MIME type text/javascript1.0
+FAIL Registering script with good MIME type text/javascript1.1 promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/javascript1.1')."
+PASS Registering script that imports script with good MIME type text/javascript1.1
+FAIL Registering script with good MIME type text/javascript1.2 promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/javascript1.2')."
+PASS Registering script that imports script with good MIME type text/javascript1.2
+FAIL Registering script with good MIME type text/javascript1.3 promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/javascript1.3')."
+PASS Registering script that imports script with good MIME type text/javascript1.3
+FAIL Registering script with good MIME type text/javascript1.4 promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/javascript1.4')."
+PASS Registering script that imports script with good MIME type text/javascript1.4
+FAIL Registering script with good MIME type text/javascript1.5 promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/javascript1.5')."
+PASS Registering script that imports script with good MIME type text/javascript1.5
+FAIL Registering script with good MIME type text/jscript promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/jscript')."
+PASS Registering script that imports script with good MIME type text/jscript
+FAIL Registering script with good MIME type text/livescript promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/livescript')."
+PASS Registering script that imports script with good MIME type text/livescript
+FAIL Registering script with good MIME type text/x-ecmascript promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/x-ecmascript')."
+PASS Registering script that imports script with good MIME type text/x-ecmascript
+FAIL Registering script with good MIME type text/x-javascript promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/x-javascript')."
+PASS Registering script that imports script with good MIME type text/x-javascript
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/threaded/compositing/visibility/visibility-image-layers-dynamic-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/threaded/compositing/visibility/visibility-image-layers-dynamic-expected.txt
index 790ed1b..22c5698 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/threaded/compositing/visibility/visibility-image-layers-dynamic-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/threaded/compositing/visibility/visibility-image-layers-dynamic-expected.txt
@@ -24,7 +24,7 @@
     },
     {
       "name": "LayoutImage IMG class='visible composited box'",
-      "position": [24, 24],
+      "position": [38, 338],
       "bounds": [100, 100]
     }
   ]
@@ -46,7 +46,7 @@
     },
     {
       "name": "LayoutImage IMG class='hidden composited box'",
-      "position": [20, 20],
+      "position": [38, 30],
       "bounds": [100, 100]
     },
     {
@@ -57,7 +57,7 @@
     },
     {
       "name": "LayoutImage IMG class='visible composited box'",
-      "position": [24, 24],
+      "position": [38, 338],
       "bounds": [100, 100]
     }
   ]
@@ -79,7 +79,7 @@
     },
     {
       "name": "LayoutImage IMG class='hidden composited box'",
-      "position": [20, 20],
+      "position": [38, 30],
       "bounds": [100, 100]
     },
     {
@@ -90,7 +90,7 @@
     },
     {
       "name": "LayoutImage IMG class='composited box'",
-      "position": [24, 24],
+      "position": [38, 184],
       "bounds": [100, 100]
     },
     {
@@ -101,7 +101,7 @@
     },
     {
       "name": "LayoutImage IMG class='visible composited box'",
-      "position": [24, 24],
+      "position": [38, 338],
       "bounds": [100, 100]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/ancestor-overflow-change-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/ancestor-overflow-change-expected.png
index ce77def2..177663ed 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/ancestor-overflow-change-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/ancestor-overflow-change-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/bounds-ignores-hidden-composited-descendant-expected.txt b/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/bounds-ignores-hidden-composited-descendant-expected.txt
index 3810e8c..a6a3e36 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/bounds-ignores-hidden-composited-descendant-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/bounds-ignores-hidden-composited-descendant-expected.txt
@@ -11,20 +11,18 @@
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited'",
       "position": [10, 10],
-      "transformOrigin": [-10, -10],
       "bounds": [590, 210],
       "drawsContent": true
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited'",
       "position": [10, 260],
-      "transformOrigin": [-10, -10],
       "bounds": [590, 210],
       "drawsContent": true
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='composited inner box'",
-      "position": [490, 110],
+      "position": [500, 370],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "drawsContent": true,
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/composited-in-columns-expected.txt b/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/composited-in-columns-expected.txt
index d9d29ac3a..aeb01ce 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/composited-in-columns-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/composited-in-columns-expected.txt
@@ -15,7 +15,7 @@
     },
     {
       "name": "LayoutBlockFlow DIV class='composited box'",
-      "position": [5, 5],
+      "position": [19, 169],
       "bounds": [50, 50],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -30,7 +30,7 @@
     },
     {
       "name": "LayoutBlockFlow DIV class='composited box'",
-      "position": [5, 5],
+      "position": [277, 94],
       "bounds": [50, 50],
       "contentsOpaque": true,
       "drawsContent": true,
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/layer-due-to-layer-children-deep-switch-expected.txt b/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/layer-due-to-layer-children-deep-switch-expected.txt
index a7451f1..66f2b4b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/layer-due-to-layer-children-deep-switch-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/layer-due-to-layer-children-deep-switch-expected.txt
@@ -30,7 +30,7 @@
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='child'",
-      "position": [31, 41],
+      "position": [39, 49],
       "bounds": [250, 220],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -43,12 +43,7 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#FFFF00",
-      "transform": [
-        [0.866025403784439, 0.5, 0, 0],
-        [-0.5, 0.866025403784439, 0, 0],
-        [0, 0, 1, 0],
-        [0, 0, 0, 1]
-      ]
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='greatgrandchild'",
@@ -57,12 +52,30 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#008000",
+      "transform": 2
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [0.866025403784439, 0.5, 0, 0],
+        [-0.5, 0.866025403784439, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, 0, 1]
+      ],
+      "origin": [100, 100]
+    },
+    {
+      "id": 2,
+      "parent": 1,
       "transform": [
         [0.5, 0, -0.866025403784439, 0.0021650635094611],
         [0, 1, 0, 0],
         [0.866025403784439, 0, 0.5, -0.00125],
         [-30, 30, 100, 0.75]
-      ]
+      ],
+      "origin": [125, 50]
     }
   ]
 }
@@ -72,7 +85,7 @@
   "layers": [
     {
       "name": "LayoutView #document",
-      "bounds": [785, 1382],
+      "bounds": [785, 1590],
       "contentsOpaque": true,
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/layer-due-to-layer-children-switch-expected.txt b/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/layer-due-to-layer-children-switch-expected.txt
index 8c8acee..d3885a4d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/layer-due-to-layer-children-switch-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/layer-due-to-layer-children-switch-expected.txt
@@ -35,12 +35,19 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#008000",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
       "transform": [
         [0.707106781186548, 0, -0.707106781186548, 0.00117851130197758],
         [0, 1, 0, 0],
         [0.707106781186548, 0, 0.707106781186548, -0.00117851130197758],
         [-50, 10, 100, 0.833333333333333]
-      ]
+      ],
+      "origin": [125, 50]
     }
   ]
 }
@@ -50,7 +57,7 @@
   "layers": [
     {
       "name": "LayoutView #document",
-      "bounds": [785, 930],
+      "bounds": [785, 1042],
       "contentsOpaque": true,
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/limit-layer-bounds-overflow-root-expected.txt b/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/limit-layer-bounds-overflow-root-expected.txt
index 6d63b12..342fa2d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/limit-layer-bounds-overflow-root-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/limit-layer-bounds-overflow-root-expected.txt
@@ -7,8 +7,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='compositing'",
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/preserve-3d-switching-expected.txt b/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/preserve-3d-switching-expected.txt
index 494773cf..59dae0f 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/preserve-3d-switching-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/preserve-3d-switching-expected.txt
@@ -18,29 +18,16 @@
     {
       "name": "Child Transform Layer",
       "bounds": [304, 304],
-      "shouldFlattenTransform": false,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, -0.002],
-        [0, 0, 0, 1]
-      ]
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow DIV id='parent'",
       "position": [12, 12],
       "bounds": [280, 280],
       "contentsOpaque": true,
-      "shouldFlattenTransform": false,
-      "3dRenderingContext": 1,
       "drawsContent": true,
       "backgroundColor": "#FFFF00",
-      "transform": [
-        [0.766044443118978, -0.556670399226419, -0.32139380484327, 0],
-        [0, 0.5, -0.866025403784439, 0],
-        [0.642787609686539, 0.663413948168938, 0.383022221559489, 0],
-        [0, 0, 0, 1]
-      ]
+      "transform": 2
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV",
@@ -48,15 +35,47 @@
       "bounds": [200, 200],
       "opacity": 0.699999988079071,
       "contentsOpaque": true,
-      "3dRenderingContext": 1,
       "drawsContent": true,
       "backgroundColor": "#008000",
+      "transform": 3
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, -0.002],
+        [0, 0, 0, 1]
+      ],
+      "origin": [152, 152],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [0.766044443118978, -0.556670399226419, -0.32139380484327, 0],
+        [0, 0.5, -0.866025403784439, 0],
+        [0.642787609686539, 0.663413948168938, 0.383022221559489, 0],
+        [0, 0, 0, 1]
+      ],
+      "origin": [140, 140],
+      "flattenInheritedTransform": false,
+      "renderingContext": 1
+    },
+    {
+      "id": 3,
+      "parent": 2,
       "transform": [
         [0.766044443118978, 0, 0.642787609686539, 0],
         [0, 1, 0, 0],
         [-0.642787609686539, 0, 0.766044443118978, 0],
         [0, 0, 50, 1]
-      ]
+      ],
+      "origin": [100, 100],
+      "renderingContext": 1
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/iframes/invisible-nested-iframe-show-expected.txt b/third_party/WebKit/LayoutTests/platform/win/compositing/iframes/invisible-nested-iframe-show-expected.txt
index f11cd18..632d2a7f 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/iframes/invisible-nested-iframe-show-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/iframes/invisible-nested-iframe-show-expected.txt
@@ -15,56 +15,64 @@
     },
     {
       "name": "Frame Overflow Controls Host Layer",
-      "position": [34, 34],
+      "position": [23, 23],
       "bounds": [300, 150]
     },
     {
       "name": "Frame Clipping Layer",
+      "position": [23, 23],
       "bounds": [285, 150]
     },
     {
-      "name": "Frame Scrolling Layer"
+      "name": "Frame Scrolling Layer",
+      "position": [23, 23]
     },
     {
       "name": "Content Root Layer",
+      "position": [23, 23],
       "bounds": [285, 193]
     },
     {
       "name": "LayoutView #document",
+      "position": [23, 23],
       "bounds": [285, 193],
       "drawsContent": true
     },
     {
       "name": "LayoutIFrame IFRAME",
-      "position": [8, 8],
+      "position": [31, 31],
       "bounds": [252, 172],
       "drawsContent": true
     },
     {
       "name": "Frame Overflow Controls Host Layer",
-      "position": [1, 1],
+      "position": [32, 32],
       "bounds": [250, 170]
     },
     {
       "name": "Frame Clipping Layer",
+      "position": [32, 32],
       "bounds": [250, 170]
     },
     {
-      "name": "Frame Scrolling Layer"
+      "name": "Frame Scrolling Layer",
+      "position": [32, 32]
     },
     {
       "name": "Content Root Layer",
+      "position": [32, 32],
       "bounds": [250, 230]
     },
     {
       "name": "LayoutView #document",
+      "position": [32, 32],
       "bounds": [250, 230],
       "drawsContent": true,
       "backgroundColor": "#C0C0C0"
     },
     {
       "name": "LayoutBlockFlow DIV id='iframe-content' class='box'",
-      "position": [18, 10],
+      "position": [50, 42],
       "bounds": [210, 210],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -72,7 +80,7 @@
     },
     {
       "name": "Frame Vertical Scrollbar Layer",
-      "position": [285, 0],
+      "position": [308, 23],
       "bounds": [15, 150]
     },
     {
@@ -82,6 +90,12 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#0000FF",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/layer-creation/fixed-position-nonscrollable-body-mismatch-containers-expected.txt b/third_party/WebKit/LayoutTests/platform/win/compositing/layer-creation/fixed-position-nonscrollable-body-mismatch-containers-expected.txt
index ebc73b8..7089229 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/layer-creation/fixed-position-nonscrollable-body-mismatch-containers-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/layer-creation/fixed-position-nonscrollable-body-mismatch-containers-expected.txt
@@ -12,37 +12,37 @@
       "name": "LayoutBlockFlow DIV class='scrollable bigBox'",
       "position": [8, 72],
       "bounds": [302, 302],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "position": [1, 1],
-      "bounds": [285, 285],
-      "shouldFlattenTransform": false
+      "position": [9, 73],
+      "bounds": [285, 285]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [9, 73],
       "bounds": [285, 800],
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 72],
       "bounds": [302, 302]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [1, 286],
+      "position": [9, 358],
       "bounds": [285, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [286, 1],
+      "position": [294, 73],
       "bounds": [15, 285]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [286, 286],
+      "position": [294, 358],
       "bounds": [15, 15],
       "drawsContent": true
     },
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/layer-creation/no-compositing-for-preserve-3d-expected.txt b/third_party/WebKit/LayoutTests/platform/win/compositing/layer-creation/no-compositing-for-preserve-3d-expected.txt
index d7fca8d0..46b03a8 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/layer-creation/no-compositing-for-preserve-3d-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/layer-creation/no-compositing-for-preserve-3d-expected.txt
@@ -13,24 +13,36 @@
       "name": "LayoutBlockFlow DIV class='preserve3d'",
       "position": [18, 394],
       "bounds": [342, 182],
-      "shouldFlattenTransform": false,
-      "3dRenderingContext": 1,
-      "drawsContent": true
+      "drawsContent": true,
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='box'",
       "position": [31, 51],
       "bounds": [100, 100],
       "contentsOpaque": true,
-      "3dRenderingContext": 1,
       "drawsContent": true,
       "backgroundColor": "#C0C0C0",
+      "transform": 2
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "flattenInheritedTransform": false,
+      "renderingContext": 1
+    },
+    {
+      "id": 2,
+      "parent": 1,
       "transform": [
         [0.984807753012208, 0, -0.17364817766693, 0],
         [0, 1, 0, 0],
         [0.17364817766693, 0, 0.984807753012208, 0],
         [0, 0, 0, 1]
-      ]
+      ],
+      "origin": [50, 50],
+      "renderingContext": 1
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/textarea-scroll-touch-expected.txt b/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/textarea-scroll-touch-expected.txt
index a505dce..42c98fa 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/textarea-scroll-touch-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/textarea-scroll-touch-expected.txt
@@ -11,34 +11,34 @@
       "name": "LayoutTextControl TEXTAREA",
       "position": [18, 18],
       "bounds": [206, 126],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#CCCCCC"
     },
     {
       "name": "Scrolling Layer",
-      "position": [1, 1],
-      "bounds": [189, 124],
-      "shouldFlattenTransform": false
+      "position": [19, 19],
+      "bounds": [189, 124]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [19, 19],
       "bounds": [189, 328],
       "contentsOpaque": true,
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [18, 18],
       "bounds": [206, 126]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [190, 1],
+      "position": [208, 19],
       "bounds": [15, 109]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [190, 110],
+      "position": [208, 128],
       "bounds": [15, 15],
       "drawsContent": true
     },
@@ -46,34 +46,34 @@
       "name": "LayoutTextControl TEXTAREA",
       "position": [248, 18],
       "bounds": [206, 126],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#CCCCCC"
     },
     {
       "name": "Scrolling Layer",
-      "position": [1, 1],
-      "bounds": [189, 124],
-      "shouldFlattenTransform": false
+      "position": [249, 19],
+      "bounds": [189, 124]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [249, 19],
       "bounds": [189, 328],
       "contentsOpaque": true,
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [248, 18],
       "bounds": [206, 126]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [190, 1],
+      "position": [438, 19],
       "bounds": [15, 109]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [190, 110],
+      "position": [438, 128],
       "bounds": [15, 15],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/squashing/no-squashing-into-another-clip-layer-expected.txt b/third_party/WebKit/LayoutTests/platform/win/compositing/squashing/no-squashing-into-another-clip-layer-expected.txt
index 7e6a1c2..ca9b5ff 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/squashing/no-squashing-into-another-clip-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/squashing/no-squashing-into-another-clip-layer-expected.txt
@@ -16,10 +16,12 @@
     },
     {
       "name": "Child Containment Layer",
+      "position": [8, 8],
       "bounds": [784, 10]
     },
     {
       "name": "LayoutBlockFlow DIV id='inner'",
+      "position": [8, 8],
       "bounds": [784, 10],
       "contentsOpaque": true,
       "drawsContent": true,
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/squashing/selection-repaint-with-gaps-expected.txt b/third_party/WebKit/LayoutTests/platform/win/compositing/squashing/selection-repaint-with-gaps-expected.txt
index ac59b00a..b680650 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/squashing/selection-repaint-with-gaps-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/squashing/selection-repaint-with-gaps-expected.txt
@@ -8,8 +8,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow DIV class='overlap'",
@@ -62,8 +61,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow DIV class='overlap'",
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/video/video-poster-expected.txt b/third_party/WebKit/LayoutTests/platform/win/compositing/video/video-poster-expected.txt
index e1dae87..34830f6 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/video/video-poster-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/video/video-poster-expected.txt
@@ -42,8 +42,7 @@
       "bounds": [352, 288]
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutFlexibleBox (relative positioned) DIV",
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/visibility/visibility-image-layers-dynamic-expected.txt b/third_party/WebKit/LayoutTests/platform/win/compositing/visibility/visibility-image-layers-dynamic-expected.txt
index a6f5968..602ad19 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/visibility/visibility-image-layers-dynamic-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/visibility/visibility-image-layers-dynamic-expected.txt
@@ -24,7 +24,7 @@
     },
     {
       "name": "LayoutImage IMG class='visible composited box'",
-      "position": [24, 24],
+      "position": [38, 340],
       "bounds": [100, 100]
     }
   ]
@@ -46,7 +46,7 @@
     },
     {
       "name": "LayoutImage IMG class='hidden composited box'",
-      "position": [20, 20],
+      "position": [38, 30],
       "bounds": [100, 100]
     },
     {
@@ -57,7 +57,7 @@
     },
     {
       "name": "LayoutImage IMG class='visible composited box'",
-      "position": [24, 24],
+      "position": [38, 340],
       "bounds": [100, 100]
     }
   ]
@@ -79,7 +79,7 @@
     },
     {
       "name": "LayoutImage IMG class='hidden composited box'",
-      "position": [20, 20],
+      "position": [38, 30],
       "bounds": [100, 100]
     },
     {
@@ -90,7 +90,7 @@
     },
     {
       "name": "LayoutImage IMG class='composited box'",
-      "position": [24, 24],
+      "position": [38, 185],
       "bounds": [100, 100]
     },
     {
@@ -101,7 +101,7 @@
     },
     {
       "name": "LayoutImage IMG class='visible composited box'",
-      "position": [24, 24],
+      "position": [38, 340],
       "bounds": [100, 100]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/platform/win/css3/blending/mix-blend-mode-composited-layers-expected.txt b/third_party/WebKit/LayoutTests/platform/win/css3/blending/mix-blend-mode-composited-layers-expected.txt
index 88c735a2..d6715a0 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css3/blending/mix-blend-mode-composited-layers-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/css3/blending/mix-blend-mode-composited-layers-expected.txt
@@ -21,6 +21,7 @@
     },
     {
       "name": "LayoutBlockFlow DIV",
+      "position": [8, 18],
       "bounds": [10, 10],
       "contentsOpaque": true,
       "drawsContent": true,
diff --git a/third_party/WebKit/LayoutTests/platform/win/css3/filters/composited-layer-child-bounds-after-composited-to-sw-shadow-change-expected.txt b/third_party/WebKit/LayoutTests/platform/win/css3/filters/composited-layer-child-bounds-after-composited-to-sw-shadow-change-expected.txt
index eeb5a7d..21c611a7 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css3/filters/composited-layer-child-bounds-after-composited-to-sw-shadow-change-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/css3/filters/composited-layer-child-bounds-after-composited-to-sw-shadow-change-expected.txt
@@ -16,6 +16,7 @@
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='absolutely-positioned-composited-child'",
+      "position": [100, 100],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -41,6 +42,7 @@
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='absolutely-positioned-composited-child'",
+      "position": [100, 100],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "drawsContent": true,
diff --git a/third_party/WebKit/LayoutTests/platform/win/editing/selection/modify_extend/extend_by_character-expected.txt b/third_party/WebKit/LayoutTests/platform/win/editing/selection/modify_extend/extend_by_character-expected.txt
index 0431646..ced8a3f2 100644
--- a/third_party/WebKit/LayoutTests/platform/win/editing/selection/modify_extend/extend_by_character-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/editing/selection/modify_extend/extend_by_character-expected.txt
@@ -1,12 +1,12 @@
 This is a testharness.js-based test.
 PASS extend forward character on characters
 PASS extend forward character through image
-FAIL extend forward character through multiple spacesLayoutTests/editing/selection/modify_extend/extend_by_character.html:42:12)
+FAIL extend forward character through multiple spaces LayoutTests/editing/selection/modify_extend/extend_by_character.html:42:12)
 	 expected <div contenteditable> <i>F    ^and seven</i> years <b>  as </b>our fathers  f upon this continent, a new nation, conceived    in Liberty,   and dedicated to the proposition that all  <br>men are created equal|. </div>,
 	 but got  <div contenteditable> <i>F    ^and seven</i> years <b>  as </b>our fathers  f upon this continent, a new nation, conceived    in Liberty,   and dedicated to the proposition that all  <br>men are created equ|al. </div>,
 	 sameupto <div contenteditable> <i>F    ^and seven</i> years <b>  as </b>our fathers  f upon this continent, a new nation, conceived    in Liberty,   and dedicated to the proposition that all  <br>men are created equ
 PASS extend backward character through image
-FAIL extend backward character through multiple spacesLayoutTests/editing/selection/modify_extend/extend_by_character.html:92:12)
+FAIL extend backward character through multiple spaces LayoutTests/editing/selection/modify_extend/extend_by_character.html:92:12)
 	 expected <div contenteditable> <i>|F    and seven</i> years <b>  as </b>our fathers  f upon this continent, a new nation, conceived    in Liberty,   and dedicated to the proposition that all  <br>men are created equ^al. </div>,
 	 but got  <div contenteditable> <i>F    |and seven</i> years <b>  as </b>our fathers  f upon this continent, a new nation, conceived    in Liberty,   and dedicated to the proposition that all  <br>men are created equ^al. </div>,
 	 sameupto <div contenteditable> <i>
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/dom/Range/getClientRects-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/dom/Range/getClientRects-expected.txt
index cc0d3b1d..d3e9a84 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/dom/Range/getClientRects-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/dom/Range/getClientRects-expected.txt
@@ -1,12 +1,12 @@
 This is a testharness.js-based test.
-FAIL range.selectNode(container) has rects for container and each line.assert_equals: Size of rect 4 should match expected expected "324x18" but got "398x18"
-FAIL range.selectNodeContents(container) has rects for each line.assert_equals: Size of rect 3 should match expected expected "324x18" but got "398x18"
+FAIL range.selectNode(container) has rects for container and each line. assert_equals: Size of rect 4 should match expected expected "324x18" but got "398x18"
+FAIL range.selectNodeContents(container) has rects for each line. assert_equals: Size of rect 3 should match expected expected "324x18" but got "398x18"
 PASS range.setStart/setEnd(node, offset) has rects for each line in range.
 PASS range.selectNode(container) should not include rect of image.
 PASS range.setStart/setEnd(node, offset) should include rect of image.
 PASS range.selectNode(container) should not include green/blue boxes.
 PASS range.selectNodeContents() should select green but not blue box.
-FAIL transform, range.selectNodeContents() has rects for each line.assert_equals: Size of rect 3 should match expected expected "222x260" but got "270x316"
-FAIL vertical, range.selectNodeContents() has rects for each line.assert_equals: Size of rect 3 should match expected expected "18x324" but got "18x398"
+FAIL transform, range.selectNodeContents() has rects for each line. assert_equals: Size of rect 3 should match expected expected "222x260" but got "270x316"
+FAIL vertical, range.selectNodeContents() has rects for each line. assert_equals: Size of rect 3 should match expected expected "18x324" but got "18x398"
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/canvas-composite-repaint-by-all-imagesource-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/canvas-composite-repaint-by-all-imagesource-expected.txt
index 911d579b..1007469 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/canvas-composite-repaint-by-all-imagesource-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/canvas-composite-repaint-by-all-imagesource-expected.txt
@@ -235,8 +235,7 @@
       "bounds": [150, 60]
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutFlexibleBox (relative positioned) DIV",
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-with-composited-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-with-composited-scroll-expected.txt
index d341afd0..ca1e233 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-with-composited-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-with-composited-scroll-expected.txt
@@ -10,16 +10,16 @@
       "name": "LayoutBlockFlow DIV id='scroller'",
       "position": [8, 48],
       "bounds": [100, 100],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [100, 100],
-      "shouldFlattenTransform": false
+      "position": [8, 48],
+      "bounds": [100, 100]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 48],
       "bounds": [205, 1022],
       "drawsContent": true,
       "paintInvalidations": [
@@ -37,17 +37,18 @@
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 48],
       "bounds": [100, 100]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [0, 100],
+      "position": [8, 148],
       "bounds": [100, 0],
       "drawsContent": true
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [100, 0],
+      "position": [108, 48],
       "bounds": [0, 100],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/composited-table-row-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/composited-table-row-expected.txt
index 7a21c5a..d35ae66 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/composited-table-row-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/composited-table-row-expected.txt
@@ -9,7 +9,6 @@
     {
       "name": "LayoutTableRow TR",
       "position": [8, 8],
-      "transformOrigin": [34.5, 11.5],
       "bounds": [70, 24],
       "drawsContent": true,
       "backgroundColor": "#FF0000",
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt
index 95753a2..cd60ca514 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt
@@ -7,8 +7,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow DIV id='foo'",
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/compositing/remove-squashed-layer-plus-move-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/compositing/remove-squashed-layer-plus-move-expected.txt
index 5c1b5b89c..7435964 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/compositing/remove-squashed-layer-plus-move-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/compositing/remove-squashed-layer-plus-move-expected.txt
@@ -24,8 +24,7 @@
       ]
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV",
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/offset-change-wrong-invalidation-with-float-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/offset-change-wrong-invalidation-with-float-expected.txt
index 19157495..9a8f24d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/offset-change-wrong-invalidation-with-float-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/offset-change-wrong-invalidation-with-float-expected.txt
@@ -31,13 +31,12 @@
     {
       "name": "LayoutListItem (floating) LI id='watches'",
       "position": [30, 44],
-      "transformOrigin": [18, 10],
       "bounds": [25, 19],
       "drawsContent": true
     },
     {
       "name": "LayoutInline (relative positioned) SPAN id='placeholder'",
-      "position": [18, 0],
+      "position": [48, 44],
       "backfaceVisibility": "hidden"
     },
     {
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/overflow-scroll-local-background-text-color-change-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/overflow-scroll-local-background-text-color-change-expected.txt
index 1df54e65..7e31c50c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/overflow-scroll-local-background-text-color-change-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/overflow-scroll-local-background-text-color-change-expected.txt
@@ -10,7 +10,6 @@
       "name": "LayoutBlockFlow DIV id='scroller'",
       "position": [8, 8],
       "bounds": [200, 200],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#0000FF",
       "paintInvalidations": [
@@ -23,11 +22,12 @@
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [185, 185],
-      "shouldFlattenTransform": false
+      "position": [8, 8],
+      "bounds": [185, 185]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 8],
       "bounds": [185, 552],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -41,11 +41,12 @@
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 8],
       "bounds": [200, 200]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [0, 185],
+      "position": [8, 193],
       "bounds": [185, 15],
       "paintInvalidations": [
         {
@@ -57,7 +58,7 @@
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [185, 0],
+      "position": [193, 8],
       "bounds": [15, 185],
       "paintInvalidations": [
         {
@@ -74,7 +75,7 @@
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [185, 185],
+      "position": [193, 193],
       "bounds": [15, 15],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/selection/selection-within-composited-scroller-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/selection/selection-within-composited-scroller-expected.txt
index 800e803b..31bfca1f 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/selection/selection-within-composited-scroller-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/selection/selection-within-composited-scroller-expected.txt
@@ -10,17 +10,17 @@
       "name": "LayoutBlockFlow DIV id='scroller'",
       "position": [8, 8],
       "bounds": [200, 200],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#D3D3D3"
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [185, 185],
-      "shouldFlattenTransform": false
+      "position": [8, 8],
+      "bounds": [185, 185]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 8],
       "bounds": [200, 1620],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -34,21 +34,22 @@
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 8],
       "bounds": [200, 200]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [0, 185],
+      "position": [8, 193],
       "bounds": [185, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [185, 0],
+      "position": [193, 8],
       "bounds": [15, 185]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [185, 185],
+      "position": [193, 193],
       "bounds": [15, 15],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/transform-focus-ring-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/transform-focus-ring-repaint-expected.txt
index 5604acb..88a792a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/transform-focus-ring-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/transform-focus-ring-repaint-expected.txt
@@ -29,16 +29,22 @@
     {
       "name": "LayoutBlockFlow (positioned) DIV",
       "position": [108, 158],
-      "transformOrigin": [150, 150],
       "bounds": [440, 300],
       "drawsContent": true,
       "backgroundColor": "#0000FF",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
       "transform": [
         [0, 1, 0, 0],
         [-1, 0, 0, 0],
         [0, 0, 1, 0],
         [0, 0, 0, 1]
-      ]
+      ],
+      "origin": [150, 150]
     }
   ],
   "objectPaintInvalidations": [
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/table/composited-table-background-composited-row-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/table/composited-table-background-composited-row-expected.txt
index f6ccb23f..eea77cc 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/table/composited-table-background-composited-row-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/table/composited-table-background-composited-row-expected.txt
@@ -22,7 +22,7 @@
     },
     {
       "name": "LayoutTableCell TD",
-      "position": [63, 0],
+      "position": [71, 96],
       "bounds": [58, 64],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/table/composited-table-background-composited-row-initial-empty-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/table/composited-table-background-composited-row-initial-empty-expected.txt
index f6ccb23f..eea77cc 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/table/composited-table-background-composited-row-initial-empty-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/table/composited-table-background-composited-row-initial-empty-expected.txt
@@ -22,7 +22,7 @@
     },
     {
       "name": "LayoutTableCell TD",
-      "position": [63, 0],
+      "position": [71, 96],
       "bounds": [58, 64],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/table/composited-table-background-section-composited-row-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/table/composited-table-background-section-composited-row-expected.txt
index 1faa0f8..0ae1068 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/table/composited-table-background-section-composited-row-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/table/composited-table-background-section-composited-row-expected.txt
@@ -22,13 +22,13 @@
     },
     {
       "name": "LayoutTableRow TR",
-      "position": [0, 68],
+      "position": [8, 96],
       "bounds": [184, 64],
       "drawsContent": true
     },
     {
       "name": "LayoutTableCell TD",
-      "position": [63, 0],
+      "position": [71, 96],
       "bounds": [58, 64],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/table/composited-table-background-section-composited-row-initial-empty-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/table/composited-table-background-section-composited-row-initial-empty-expected.txt
index 1faa0f8..0ae1068 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/table/composited-table-background-section-composited-row-initial-empty-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/table/composited-table-background-section-composited-row-initial-empty-expected.txt
@@ -22,13 +22,13 @@
     },
     {
       "name": "LayoutTableRow TR",
-      "position": [0, 68],
+      "position": [8, 96],
       "bounds": [184, 64],
       "drawsContent": true
     },
     {
       "name": "LayoutTableCell TD",
-      "position": [63, 0],
+      "position": [71, 96],
       "bounds": [58, 64],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/table/composited-table-background-section-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/table/composited-table-background-section-expected.txt
index 488d0669..4c9b4ebb 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/table/composited-table-background-section-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/table/composited-table-background-section-expected.txt
@@ -22,7 +22,7 @@
     },
     {
       "name": "LayoutTableCell TD",
-      "position": [63, 68],
+      "position": [71, 96],
       "bounds": [58, 64],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/table/composited-table-background-section-initial-empty-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/table/composited-table-background-section-initial-empty-expected.txt
index 488d0669..4c9b4ebb 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/table/composited-table-background-section-initial-empty-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/table/composited-table-background-section-initial-empty-expected.txt
@@ -22,7 +22,7 @@
     },
     {
       "name": "LayoutTableCell TD",
-      "position": [63, 68],
+      "position": [71, 96],
       "bounds": [58, 64],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/video-mute-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/video-mute-repaint-expected.txt
index bef8e7d..dd9466e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/video-mute-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/video-mute-repaint-expected.txt
@@ -19,8 +19,7 @@
       "bounds": [700, 525]
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutFlexibleBox (relative positioned) DIV",
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/video-paint-invalidation-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/video-paint-invalidation-expected.txt
index 9fa92010..15d02f8 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/video-paint-invalidation-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/video-paint-invalidation-expected.txt
@@ -12,8 +12,7 @@
       "bounds": [320, 240]
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutFlexibleBox (relative positioned) DIV",
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/video-unmute-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/video-unmute-repaint-expected.txt
index 34c8f42..ef70c70 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/video-unmute-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/video-unmute-repaint-expected.txt
@@ -19,8 +19,7 @@
       "bounds": [700, 525]
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutFlexibleBox (relative positioned) DIV",
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/markers/suggestion-marker-basic-expected.png b/third_party/WebKit/LayoutTests/platform/win/paint/markers/suggestion-marker-basic-expected.png
new file mode 100644
index 0000000..d572765b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/markers/suggestion-marker-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/markers/suggestion-marker-basic-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/markers/suggestion-marker-basic-expected.txt
new file mode 100644
index 0000000..0612435
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/markers/suggestion-marker-basic-expected.txt
@@ -0,0 +1,102 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x460
+  LayoutBlockFlow {HTML} at (0,0) size 800x460
+    LayoutBlockFlow {BODY} at (8,8) size 784x0
+      LayoutBlockFlow (floating) {DIV} at (598,0) size 186x192
+        LayoutBlockFlow {P} at (0,16) size 186x20
+          LayoutText {#text} at (158,0) size 28x19
+            text run at (158,0) width 28: "RTL"
+        LayoutBlockFlow {DIV} at (0,52) size 186x20
+          LayoutText {#text} at (121,0) size 65x19
+            text run at (121,0) width 65: "markRtlAll"
+        LayoutBlockFlow {DIV} at (0,72) size 186x20
+          LayoutText {#text} at (87,0) size 99x19
+            text run at (87,0) width 99: "markRtlAllThick"
+        LayoutBlockFlow {DIV} at (0,92) size 186x20
+          LayoutText {#text} at (80,0) size 106x19
+            text run at (80,0) width 106: "markRtlBeginning"
+        LayoutBlockFlow {DIV} at (0,112) size 186x20
+          LayoutText {#text} at (0,0) size 186x19
+            text run at (0,0) width 186: "markRtlAllExceptFirstAndLast"
+        LayoutBlockFlow {DIV} at (0,132) size 186x20
+          LayoutText {#text} at (114,0) size 72x19
+            text run at (114,0) width 72: "markRtlEnd"
+        LayoutBlockFlow {DIV} at (0,152) size 186x40
+          LayoutBlockFlow {DIV} at (0,0) size 186x20
+            LayoutText {#text} at (138,0) size 31x19
+              text run at (138,0) width 31: "mark"
+            LayoutInline {SPAN} at (0,0) size 17x19
+              LayoutText {#text} at (169,0) size 17x19
+                text run at (169,0) width 17: "Rtl"
+          LayoutBlockFlow {DIV} at (0,20) size 186x20
+            LayoutText {#text} at (102,0) size 84x19
+              text run at (102,0) width 84: "AcrossNodes"
+      LayoutBlockFlow (floating) {DIV} at (0,0) size 310x452
+        LayoutBlockFlow {P} at (0,16) size 310x20
+          LayoutText {#text} at (0,0) size 27x19
+            text run at (0,0) width 27: "LTR"
+        LayoutBlockFlow {DIV} at (0,52) size 310x20
+          LayoutText {#text} at (0,0) size 48x19
+            text run at (0,0) width 48: "markAll"
+        LayoutBlockFlow {DIV} at (0,72) size 310x20
+          LayoutText {#text} at (0,0) size 82x19
+            text run at (0,0) width 82: "markAllThick"
+        LayoutBlockFlow {DIV} at (0,92) size 310x20
+          LayoutText {#text} at (0,0) size 141x19
+            text run at (0,0) width 141: "markAllDifferentColors"
+        LayoutBlockFlow {DIV} at (0,112) size 310x20
+          LayoutText {#text} at (0,0) size 89x19
+            text run at (0,0) width 89: "markBeginning"
+        LayoutBlockFlow {DIV} at (0,132) size 310x20
+          LayoutText {#text} at (0,0) size 169x19
+            text run at (0,0) width 169: "markAllExceptFirstAndLast"
+        LayoutBlockFlow {DIV} at (0,152) size 310x20
+          LayoutText {#text} at (0,0) size 55x19
+            text run at (0,0) width 55: "markEnd"
+        LayoutBlockFlow {DIV} at (0,172) size 310x20
+          LayoutText {#text} at (0,0) size 108x19
+            text run at (0,0) width 108: "markNothingZero"
+        LayoutBlockFlow {DIV} at (0,192) size 310x20
+          LayoutText {#text} at (0,0) size 103x19
+            text run at (0,0) width 103: "markNothingEnd"
+        LayoutBlockFlow {DIV} at (0,212) size 310x40
+          LayoutBlockFlow {DIV} at (0,0) size 310x20
+            LayoutText {#text} at (0,0) size 31x19
+              text run at (0,0) width 31: "mark"
+            LayoutInline {SPAN} at (0,0) size 43x19
+              LayoutText {#text} at (31,0) size 43x19
+                text run at (31,0) width 43: "Across"
+          LayoutBlockFlow {DIV} at (0,20) size 310x20
+            LayoutText {#text} at (0,0) size 41x19
+              text run at (0,0) width 41: "Nodes"
+        LayoutBlockFlow {DIV} at (0,252) size 310x20
+          LayoutText {#text} at (0,0) size 226x19
+            text run at (0,0) width 226: "overridingSpellingMarkerAtBeginning"
+        LayoutBlockFlow {DIV} at (0,272) size 310x20
+          LayoutText {#text} at (0,0) size 192x19
+            text run at (0,0) width 192: "overridingSpellingMarkerAtEnd"
+        LayoutBlockFlow {DIV} at (0,292) size 310x20
+          LayoutText {#text} at (0,0) size 280x19
+            text run at (0,0) width 280: "overridingSpellingMarkerIntersectingBeginning"
+        LayoutBlockFlow {DIV} at (0,312) size 310x20
+          LayoutText {#text} at (0,0) size 246x19
+            text run at (0,0) width 246: "overridingSpellingMarkerIntersectingEnd"
+        LayoutBlockFlow {DIV} at (0,332) size 310x20
+          LayoutText {#text} at (0,0) size 236x19
+            text run at (0,0) width 236: "notOverridingSpellingMarkersTouching"
+        LayoutBlockFlow {DIV} at (0,352) size 310x20
+          LayoutText {#text} at (0,0) size 256x19
+            text run at (0,0) width 256: "overridingCompositionMarkerAtBeginning"
+        LayoutBlockFlow {DIV} at (0,372) size 310x20
+          LayoutText {#text} at (0,0) size 222x19
+            text run at (0,0) width 222: "overridingCompositionMarkerAtEnd"
+        LayoutBlockFlow {DIV} at (0,392) size 310x20
+          LayoutText {#text} at (0,0) size 310x19
+            text run at (0,0) width 310: "overridingCompositionMarkerIntersectingBeginning"
+        LayoutBlockFlow {DIV} at (0,412) size 310x20
+          LayoutText {#text} at (0,0) size 276x19
+            text run at (0,0) width 276: "overridingCompositionMarkerIntersectingEnd"
+        LayoutBlockFlow {DIV} at (0,432) size 310x20
+          LayoutText {#text} at (0,0) size 266x19
+            text run at (0,0) width 266: "notOverridingCompositionMarkersTouching"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/ancestor-overflow-change-expected.png b/third_party/WebKit/LayoutTests/platform/win/paint/markers/suggestion-marker-split-expected.png
similarity index 64%
copy from third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/ancestor-overflow-change-expected.png
copy to third_party/WebKit/LayoutTests/platform/win/paint/markers/suggestion-marker-split-expected.png
index ce77def2..5f55a19 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/ancestor-overflow-change-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/markers/suggestion-marker-split-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/markers/suggestion-marker-split-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/markers/suggestion-marker-split-expected.txt
new file mode 100644
index 0000000..bb72732
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/markers/suggestion-marker-split-expected.txt
@@ -0,0 +1,20 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x56
+  LayoutBlockFlow {HTML} at (0,0) size 800x56
+    LayoutBlockFlow {BODY} at (8,8) size 784x40
+      LayoutBlockFlow {DIV} at (0,0) size 784x20
+        LayoutText {#text} at (0,0) size 22x19
+          text run at (0,0) width 22: "abc"
+        LayoutText {#text} at (22,0) size 29x19
+          text run at (22,0) width 29: " xxx "
+        LayoutText {#text} at (51,0) size 19x19
+          text run at (51,0) width 19: "def"
+layer at (8,28) size 128x20 scrollWidth 150
+  LayoutBlockFlow {DIV} at (0,20) size 128x20
+    LayoutText {#text} at (0,0) size 58x19
+      text run at (0,0) width 58: "abcdefghi"
+    LayoutText {#text} at (58,0) size 29x19
+      text run at (58,0) width 29: " xxx "
+    LayoutText {#text} at (87,0) size 62x19
+      text run at (87,0) width 62: "jklmnopqr"
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-parent-with-non-stacking-context-composited-ancestor-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-parent-with-non-stacking-context-composited-ancestor-expected.png
deleted file mode 100644
index fed3e19..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-parent-with-non-stacking-context-composited-ancestor-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrollbar-layer-placement-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrollbar-layer-placement-expected.txt
deleted file mode 100644
index cd12323f..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrollbar-layer-placement-expected.txt
+++ /dev/null
@@ -1,208 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true
-    },
-    {
-      "name": "LayoutBlockFlow (positioned) DIV class='outer A'",
-      "position": [6, 6],
-      "bounds": [340, 282],
-      "drawsContent": true
-    },
-    {
-      "name": "LayoutBlockFlow (relative positioned) DIV class='scroller'",
-      "position": [32, 32],
-      "bounds": [278, 218],
-      "shouldFlattenTransform": false,
-      "drawsContent": true,
-      "backgroundColor": "#FFFFFF"
-    },
-    {
-      "name": "Scrolling Layer",
-      "position": [29, 29],
-      "bounds": [220, 160],
-      "shouldFlattenTransform": false
-    },
-    {
-      "name": "Scrolling Contents Layer",
-      "bounds": [220, 236],
-      "drawsContent": true
-    },
-    {
-      "name": "Overflow Controls Host Layer",
-      "position": [24, 24],
-      "bounds": [230, 170]
-    },
-    {
-      "name": "Vertical Scrollbar Layer",
-      "position": [218, 5],
-      "bounds": [7, 160]
-    },
-    {
-      "name": "LayoutBlockFlow (positioned) DIV class='outer B'",
-      "position": [355, 6],
-      "bounds": [340, 282],
-      "drawsContent": true
-    },
-    {
-      "name": "LayoutBlockFlow DIV class='scroller'",
-      "position": [32, 32],
-      "bounds": [278, 218],
-      "shouldFlattenTransform": false,
-      "drawsContent": true,
-      "backgroundColor": "#FFFFFF"
-    },
-    {
-      "name": "Scrolling Layer",
-      "position": [29, 29],
-      "bounds": [220, 160],
-      "shouldFlattenTransform": false
-    },
-    {
-      "name": "Scrolling Contents Layer",
-      "bounds": [220, 236],
-      "drawsContent": true
-    },
-    {
-      "name": "LayoutBlockFlow (relative positioned) DIV class='content'",
-      "position": [73, 73],
-      "bounds": [196, 212],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "backgroundColor": "#DDDDDD"
-    },
-    {
-      "name": "Overflow Controls Host Layer",
-      "position": [56, 56],
-      "bounds": [230, 170]
-    },
-    {
-      "name": "Vertical Scrollbar Layer",
-      "position": [218, 5],
-      "bounds": [7, 160]
-    },
-    {
-      "name": "LayoutBlockFlow (positioned) DIV class='outer C'",
-      "position": [6, 297],
-      "bounds": [340, 282],
-      "drawsContent": true
-    },
-    {
-      "name": "Ancestor Clipping Layer",
-      "position": [40, 40],
-      "bounds": [260, 100],
-      "shouldFlattenTransform": false
-    },
-    {
-      "name": "LayoutBlockFlow DIV class='scroller'",
-      "position": [-9, -9],
-      "bounds": [278, 218],
-      "shouldFlattenTransform": false,
-      "drawsContent": true,
-      "backgroundColor": "#FFFFFF"
-    },
-    {
-      "name": "Scrolling Layer",
-      "position": [29, 29],
-      "bounds": [220, 160],
-      "shouldFlattenTransform": false
-    },
-    {
-      "name": "Scrolling Contents Layer",
-      "bounds": [220, 236],
-      "drawsContent": true
-    },
-    {
-      "name": "LayoutBlockFlow (relative positioned) DIV class='content'",
-      "position": [72, 72],
-      "bounds": [196, 212],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "backgroundColor": "#DDDDDD"
-    },
-    {
-      "name": "Overflow Controls Ancestor Clipping Layer",
-      "position": [40, 40],
-      "bounds": [260, 100]
-    },
-    {
-      "name": "Overflow Controls Host Layer",
-      "position": [15, 15],
-      "bounds": [230, 170]
-    },
-    {
-      "name": "Vertical Scrollbar Layer",
-      "position": [218, 5],
-      "bounds": [7, 160]
-    },
-    {
-      "name": "LayoutBlockFlow (positioned) DIV class='outer D'",
-      "position": [355, 297],
-      "bounds": [340, 282],
-      "drawsContent": true
-    },
-    {
-      "name": "LayoutBlockFlow (relative positioned) DIV class='clipper'",
-      "position": [24, 24],
-      "bounds": [292, 200],
-      "drawsContent": true
-    },
-    {
-      "name": "Child Containment Layer",
-      "position": [10, 10],
-      "bounds": [272, 180]
-    },
-    {
-      "name": "Ancestor Clipping Layer",
-      "position": [6, 6],
-      "bounds": [260, 100],
-      "shouldFlattenTransform": false
-    },
-    {
-      "name": "LayoutBlockFlow DIV class='scroller'",
-      "position": [-9, -9],
-      "bounds": [278, 218],
-      "shouldFlattenTransform": false,
-      "drawsContent": true,
-      "backgroundColor": "#FFFFFF"
-    },
-    {
-      "name": "Scrolling Layer",
-      "position": [29, 29],
-      "bounds": [220, 160],
-      "shouldFlattenTransform": false
-    },
-    {
-      "name": "Scrolling Contents Layer",
-      "bounds": [220, 236],
-      "drawsContent": true
-    },
-    {
-      "name": "LayoutBlockFlow (relative positioned) DIV class='content'",
-      "position": [72, 72],
-      "bounds": [196, 212],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "backgroundColor": "#DDDDDD"
-    },
-    {
-      "name": "Overflow Controls Ancestor Clipping Layer",
-      "position": [40, 40],
-      "bounds": [260, 100]
-    },
-    {
-      "name": "Overflow Controls Host Layer",
-      "position": [15, 15],
-      "bounds": [230, 170]
-    },
-    {
-      "name": "Vertical Scrollbar Layer",
-      "position": [218, 5],
-      "bounds": [7, 160]
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
index a505dce..42c98fa 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
@@ -11,34 +11,34 @@
       "name": "LayoutTextControl TEXTAREA",
       "position": [18, 18],
       "bounds": [206, 126],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#CCCCCC"
     },
     {
       "name": "Scrolling Layer",
-      "position": [1, 1],
-      "bounds": [189, 124],
-      "shouldFlattenTransform": false
+      "position": [19, 19],
+      "bounds": [189, 124]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [19, 19],
       "bounds": [189, 328],
       "contentsOpaque": true,
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [18, 18],
       "bounds": [206, 126]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [190, 1],
+      "position": [208, 19],
       "bounds": [15, 109]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [190, 110],
+      "position": [208, 128],
       "bounds": [15, 15],
       "drawsContent": true
     },
@@ -46,34 +46,34 @@
       "name": "LayoutTextControl TEXTAREA",
       "position": [248, 18],
       "bounds": [206, 126],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#CCCCCC"
     },
     {
       "name": "Scrolling Layer",
-      "position": [1, 1],
-      "bounds": [189, 124],
-      "shouldFlattenTransform": false
+      "position": [249, 19],
+      "bounds": [189, 124]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [249, 19],
       "bounds": [189, 328],
       "contentsOpaque": true,
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [248, 18],
       "bounds": [206, 126]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [190, 1],
+      "position": [438, 19],
       "bounds": [15, 109]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [190, 110],
+      "position": [438, 128],
       "bounds": [15, 15],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/threaded/compositing/visibility/visibility-image-layers-dynamic-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/threaded/compositing/visibility/visibility-image-layers-dynamic-expected.txt
index a6f5968..602ad19 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/threaded/compositing/visibility/visibility-image-layers-dynamic-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/threaded/compositing/visibility/visibility-image-layers-dynamic-expected.txt
@@ -24,7 +24,7 @@
     },
     {
       "name": "LayoutImage IMG class='visible composited box'",
-      "position": [24, 24],
+      "position": [38, 340],
       "bounds": [100, 100]
     }
   ]
@@ -46,7 +46,7 @@
     },
     {
       "name": "LayoutImage IMG class='hidden composited box'",
-      "position": [20, 20],
+      "position": [38, 30],
       "bounds": [100, 100]
     },
     {
@@ -57,7 +57,7 @@
     },
     {
       "name": "LayoutImage IMG class='visible composited box'",
-      "position": [24, 24],
+      "position": [38, 340],
       "bounds": [100, 100]
     }
   ]
@@ -79,7 +79,7 @@
     },
     {
       "name": "LayoutImage IMG class='hidden composited box'",
-      "position": [20, 20],
+      "position": [38, 30],
       "bounds": [100, 100]
     },
     {
@@ -90,7 +90,7 @@
     },
     {
       "name": "LayoutImage IMG class='composited box'",
-      "position": [24, 24],
+      "position": [38, 185],
       "bounds": [100, 100]
     },
     {
@@ -101,7 +101,7 @@
     },
     {
       "name": "LayoutImage IMG class='visible composited box'",
-      "position": [24, 24],
+      "position": [38, 340],
       "bounds": [100, 100]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/svg/css/getComputedStyle-listing-expected.txt b/third_party/WebKit/LayoutTests/svg/css/getComputedStyle-listing-expected.txt
index c86c3642..0b72264b 100644
--- a/third_party/WebKit/LayoutTests/svg/css/getComputedStyle-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/svg/css/getComputedStyle-listing-expected.txt
@@ -48,7 +48,7 @@
 -webkit-text-combine: none
 -webkit-text-decorations-in-effect: none
 -webkit-text-emphasis-color: rgb(0, 0, 0)
--webkit-text-emphasis-position: over
+-webkit-text-emphasis-position: over right
 -webkit-text-emphasis-style: none
 -webkit-text-fill-color: rgb(0, 0, 0)
 -webkit-text-orientation: vertical-right
diff --git a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/clear-scroll-parent-expected.txt b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/clear-scroll-parent-expected.txt
index 86a7938..445cdfbc 100644
--- a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/clear-scroll-parent-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/clear-scroll-parent-expected.txt
@@ -10,33 +10,33 @@
       "name": "LayoutBlockFlow DIV class='container'",
       "position": [8, 8],
       "bounds": [308, 208],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#00FF0080"
     },
     {
       "name": "Scrolling Layer",
-      "position": [4, 4],
-      "bounds": [285, 200],
-      "shouldFlattenTransform": false
+      "position": [12, 12],
+      "bounds": [285, 200]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [12, 12],
       "bounds": [285, 530],
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 8],
       "bounds": [308, 208]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [289, 4],
+      "position": [297, 12],
       "bounds": [15, 185]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [289, 189],
+      "position": [297, 197],
       "bounds": [15, 15],
       "drawsContent": true
     },
@@ -52,19 +52,17 @@
       "name": "Ancestor Clipping Layer",
       "position": [12, 12],
       "bounds": [80, 80],
-      "shouldFlattenTransform": false,
       "hasScrollParent": true
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='box red'",
-      "position": [10, 10],
+      "position": [22, 22],
       "bounds": [100, 100],
       "drawsContent": true,
       "backgroundColor": "#FF000080"
     },
     {
       "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false,
       "hasScrollParent": true
     },
     {
diff --git a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/clip-descendents-expected.txt b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/clip-descendents-expected.txt
index 995a3ddf..4d1409d 100644
--- a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/clip-descendents-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/clip-descendents-expected.txt
@@ -9,8 +9,7 @@
     {
       "name": "Ancestor Clipping Layer",
       "position": [48, 38],
-      "bounds": [60, 70],
-      "shouldFlattenTransform": false
+      "bounds": [60, 70]
     },
     {
       "name": "LayoutBlockFlow DIV class='box'",
@@ -19,18 +18,12 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#808080",
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [0, 0, 1, 1]
-      ]
+      "transform": 1
     },
     {
       "name": "Ancestor Clipping Layer",
       "position": [240, 38],
-      "bounds": [60, 70],
-      "shouldFlattenTransform": false
+      "bounds": [60, 70]
     },
     {
       "name": "LayoutBlockFlow DIV class='box'",
@@ -39,12 +32,7 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#808080",
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [0, 0, 1, 1]
-      ]
+      "transform": 2
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='container'",
@@ -54,6 +42,7 @@
     },
     {
       "name": "Child Containment Layer",
+      "position": [48, 230],
       "bounds": [60, 70]
     },
     {
@@ -63,12 +52,7 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#808080",
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [0, 0, 1, 1]
-      ]
+      "transform": 3
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='container'",
@@ -78,6 +62,7 @@
     },
     {
       "name": "Child Containment Layer",
+      "position": [240, 230],
       "bounds": [60, 70]
     },
     {
@@ -87,6 +72,39 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "backgroundColor": "#808080",
+      "transform": 4
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, 1, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, 1, 1]
+      ]
+    },
+    {
+      "id": 3,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, 1, 1]
+      ]
+    },
+    {
+      "id": 4,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
diff --git a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/composited-scrolling-paint-phases-expected.txt b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/composited-scrolling-paint-phases-expected.txt
index 530bce2..24541e10 100644
--- a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/composited-scrolling-paint-phases-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/composited-scrolling-paint-phases-expected.txt
@@ -47,7 +47,6 @@
       "name": "LayoutBlockFlow DIV class='container'",
       "position": [28, 20],
       "bounds": [202, 202],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "paintingPhases": [
         "GraphicsLayerPaintBackground",
@@ -58,9 +57,8 @@
     },
     {
       "name": "Scrolling Layer",
-      "position": [1, 1],
+      "position": [29, 21],
       "bounds": [185, 185],
-      "shouldFlattenTransform": false,
       "paintingPhases": [
         "GraphicsLayerPaintBackground",
         "GraphicsLayerPaintForeground",
@@ -70,6 +68,7 @@
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [29, 21],
       "bounds": [185, 715],
       "drawsContent": true,
       "paintingPhases": [
@@ -80,6 +79,7 @@
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [28, 20],
       "bounds": [202, 202],
       "paintingPhases": [
         "GraphicsLayerPaintBackground",
@@ -90,7 +90,7 @@
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [1, 186],
+      "position": [29, 206],
       "bounds": [185, 15],
       "paintingPhases": [
         "GraphicsLayerPaintBackground",
@@ -101,7 +101,7 @@
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [186, 1],
+      "position": [214, 21],
       "bounds": [15, 185],
       "paintingPhases": [
         "GraphicsLayerPaintBackground",
@@ -112,7 +112,7 @@
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [186, 186],
+      "position": [214, 206],
       "bounds": [15, 15],
       "drawsContent": true,
       "paintingPhases": [
diff --git a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/content-gains-scrollbars-expected.txt b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/content-gains-scrollbars-expected.txt
index e798453..a3908c3 100644
--- a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/content-gains-scrollbars-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/content-gains-scrollbars-expected.txt
@@ -10,97 +10,103 @@
       "name": "LayoutBlockFlow (positioned) DIV class='container'",
       "position": [8, 13],
       "bounds": [100, 100],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [85, 100],
-      "shouldFlattenTransform": false
+      "position": [8, 13],
+      "bounds": [85, 100]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 13],
       "bounds": [85, 200]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='vertical' class='content tall'",
+      "position": [8, 13],
       "bounds": [10, 200]
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 13],
       "bounds": [100, 100]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [85, 0],
+      "position": [93, 13],
       "bounds": [15, 100]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='container'",
       "position": [8, 13],
       "bounds": [100, 100],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [100, 85],
-      "shouldFlattenTransform": false
+      "position": [8, 13],
+      "bounds": [100, 85]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 13],
       "bounds": [200, 85]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='horizontal' class='content wide'",
+      "position": [8, 13],
       "bounds": [200, 10]
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 13],
       "bounds": [100, 100]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [0, 85],
+      "position": [8, 98],
       "bounds": [100, 15]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='container'",
       "position": [8, 13],
       "bounds": [100, 100],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [85, 85],
-      "shouldFlattenTransform": false
+      "position": [8, 13],
+      "bounds": [85, 85]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 13],
       "bounds": [200, 200]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='both' class='content wide tall'",
+      "position": [8, 13],
       "bounds": [200, 200]
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 13],
       "bounds": [100, 100]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [0, 85],
+      "position": [8, 98],
       "bounds": [85, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [85, 0],
+      "position": [93, 13],
       "bounds": [15, 85]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [85, 85],
+      "position": [93, 98],
       "bounds": [15, 15],
       "drawsContent": true
     },
@@ -112,19 +118,22 @@
     },
     {
       "name": "Child Containment Layer",
+      "position": [8, 13],
       "bounds": [100, 100]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='content'",
+      "position": [8, 13],
       "bounds": [10, 10]
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 13],
       "bounds": [100, 100]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [85, 85],
+      "position": [93, 98],
       "bounds": [15, 15],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/content-loses-scrollbars-expected.txt b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/content-loses-scrollbars-expected.txt
index 8d230d3..479ea19 100644
--- a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/content-loses-scrollbars-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/content-loses-scrollbars-expected.txt
@@ -13,10 +13,12 @@
     },
     {
       "name": "Child Containment Layer",
+      "position": [8, 13],
       "bounds": [100, 100]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='vertical' class='content'",
+      "position": [8, 13],
       "bounds": [10, 10]
     },
     {
@@ -26,10 +28,12 @@
     },
     {
       "name": "Child Containment Layer",
+      "position": [8, 13],
       "bounds": [100, 100]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='horizontal' class='content'",
+      "position": [8, 13],
       "bounds": [10, 10]
     },
     {
@@ -39,10 +43,12 @@
     },
     {
       "name": "Child Containment Layer",
+      "position": [8, 13],
       "bounds": [100, 100]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='both' class='content'",
+      "position": [8, 13],
       "bounds": [10, 10]
     },
     {
@@ -52,10 +58,12 @@
     },
     {
       "name": "Child Containment Layer",
+      "position": [8, 13],
       "bounds": [100, 100]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='content'",
+      "position": [8, 13],
       "bounds": [10, 10]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-auto-with-touch-expected.txt b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-auto-with-touch-expected.txt
index ff9be7c..df86cf85 100644
--- a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-auto-with-touch-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-auto-with-touch-expected.txt
@@ -10,36 +10,37 @@
       "name": "LayoutBlockFlow DIV class='scroller'",
       "position": [8, 8],
       "bounds": [300, 300],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [285, 285],
-      "shouldFlattenTransform": false
+      "position": [8, 8],
+      "bounds": [285, 285]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 8],
       "bounds": [1000, 1000],
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 8],
       "bounds": [300, 300]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [0, 285],
+      "position": [8, 293],
       "bounds": [285, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [285, 0],
+      "position": [293, 8],
       "bounds": [15, 285]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [285, 285],
+      "position": [293, 293],
       "bounds": [15, 15],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-auto-with-touch-toggle-expected.txt b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-auto-with-touch-toggle-expected.txt
index ff9be7c..df86cf85 100644
--- a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-auto-with-touch-toggle-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-auto-with-touch-toggle-expected.txt
@@ -10,36 +10,37 @@
       "name": "LayoutBlockFlow DIV class='scroller'",
       "position": [8, 8],
       "bounds": [300, 300],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [285, 285],
-      "shouldFlattenTransform": false
+      "position": [8, 8],
+      "bounds": [285, 285]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 8],
       "bounds": [1000, 1000],
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 8],
       "bounds": [300, 300]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [0, 285],
+      "position": [8, 293],
       "bounds": [285, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [285, 0],
+      "position": [293, 8],
       "bounds": [15, 285]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [285, 285],
+      "position": [293, 293],
       "bounds": [15, 15],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-overlay-with-touch-expected.txt b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-overlay-with-touch-expected.txt
index ff9be7c..df86cf85 100644
--- a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-overlay-with-touch-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-overlay-with-touch-expected.txt
@@ -10,36 +10,37 @@
       "name": "LayoutBlockFlow DIV class='scroller'",
       "position": [8, 8],
       "bounds": [300, 300],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [285, 285],
-      "shouldFlattenTransform": false
+      "position": [8, 8],
+      "bounds": [285, 285]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 8],
       "bounds": [1000, 1000],
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 8],
       "bounds": [300, 300]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [0, 285],
+      "position": [8, 293],
       "bounds": [285, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [285, 0],
+      "position": [293, 8],
       "bounds": [15, 285]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [285, 285],
+      "position": [293, 293],
       "bounds": [15, 15],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-scrollbar-layers-expected.txt b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-scrollbar-layers-expected.txt
index 417a0ce..aa2b0d5 100644
--- a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-scrollbar-layers-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-scrollbar-layers-expected.txt
@@ -10,97 +10,103 @@
       "name": "LayoutBlockFlow (positioned) DIV class='container'",
       "position": [8, 13],
       "bounds": [100, 100],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [85, 100],
-      "shouldFlattenTransform": false
+      "position": [8, 13],
+      "bounds": [85, 100]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 13],
       "bounds": [85, 200]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='content tall'",
+      "position": [8, 13],
       "bounds": [10, 200]
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 13],
       "bounds": [100, 100]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [85, 0],
+      "position": [93, 13],
       "bounds": [15, 100]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='container'",
       "position": [8, 13],
       "bounds": [100, 100],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [100, 85],
-      "shouldFlattenTransform": false
+      "position": [8, 13],
+      "bounds": [100, 85]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 13],
       "bounds": [200, 85]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='content wide'",
+      "position": [8, 13],
       "bounds": [200, 10]
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 13],
       "bounds": [100, 100]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [0, 85],
+      "position": [8, 98],
       "bounds": [100, 15]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='container'",
       "position": [8, 13],
       "bounds": [100, 100],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [85, 85],
-      "shouldFlattenTransform": false
+      "position": [8, 13],
+      "bounds": [85, 85]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 13],
       "bounds": [200, 200]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='content wide tall'",
+      "position": [8, 13],
       "bounds": [200, 200]
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 13],
       "bounds": [100, 100]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [0, 85],
+      "position": [8, 98],
       "bounds": [85, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [85, 0],
+      "position": [93, 13],
       "bounds": [15, 85]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [85, 85],
+      "position": [93, 98],
       "bounds": [15, 15],
       "drawsContent": true
     },
@@ -112,19 +118,22 @@
     },
     {
       "name": "Child Containment Layer",
+      "position": [8, 13],
       "bounds": [100, 100]
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='content'",
+      "position": [8, 13],
       "bounds": [10, 10]
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 13],
       "bounds": [100, 100]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [85, 85],
+      "position": [93, 98],
       "bounds": [15, 15],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/reparented-scrollbars-non-sc-anc-expected.txt b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/reparented-scrollbars-non-sc-anc-expected.txt
index d178fd3..ce8c20e 100644
--- a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/reparented-scrollbars-non-sc-anc-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/reparented-scrollbars-non-sc-anc-expected.txt
@@ -9,36 +9,38 @@
     {
       "name": "Ancestor Clipping Layer",
       "position": [8, 8],
-      "bounds": [1200, 800],
-      "shouldFlattenTransform": false
+      "bounds": [1200, 800]
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='positioned'",
+      "position": [8, 8],
       "bounds": [1200, 800],
       "drawsContent": true
     },
     {
       "name": "Child Containment Layer",
+      "position": [8, 8],
       "bounds": [1200, 800]
     },
     {
       "name": "Ancestor Clipping Layer",
-      "bounds": [1200, 1000],
-      "shouldFlattenTransform": false
+      "position": [8, 8],
+      "bounds": [1200, 1000]
     },
     {
       "name": "LayoutBlockFlow DIV id='scroller'",
+      "position": [8, 8],
       "bounds": [1200, 1000],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [1200, 1000],
-      "shouldFlattenTransform": false
+      "position": [8, 8],
+      "bounds": [1200, 1000]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 8],
       "bounds": [1200, 10000],
       "drawsContent": true
     },
@@ -54,11 +56,12 @@
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 8],
       "bounds": [1200, 1000]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [1193, 0],
+      "position": [1201, 8],
       "bounds": [7, 1000]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/resize-painting-expected.txt b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/resize-painting-expected.txt
index 7a929ee0..d7b0088d0 100644
--- a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/resize-painting-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/resize-painting-expected.txt
@@ -14,11 +14,12 @@
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [18, 10],
       "bounds": [100, 100]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [85, 85],
+      "position": [103, 95],
       "bounds": [15, 15],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-parent-absolute-expected.txt b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-parent-absolute-expected.txt
index 710d0933..c0ca36e 100644
--- a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-parent-absolute-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-parent-absolute-expected.txt
@@ -7,45 +7,45 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow DIV id='top'",
       "position": [8, 8],
       "bounds": [500, 500],
-      "shouldFlattenTransform": false,
       "drawsContent": true,
       "backgroundColor": "#0000FF"
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [485, 485],
-      "shouldFlattenTransform": false
+      "position": [8, 8],
+      "bounds": [485, 485]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 8],
       "bounds": [485, 5000],
       "contentsOpaque": true,
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 8],
       "bounds": [500, 500]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [0, 485],
+      "position": [8, 493],
       "bounds": [485, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [485, 0],
+      "position": [493, 8],
       "bounds": [15, 485]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [485, 485],
+      "position": [493, 493],
       "bounds": [15, 15],
       "drawsContent": true
     },
diff --git a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-parent-absolute-with-backdrop-filter-expected.txt b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-parent-absolute-with-backdrop-filter-expected.txt
index 9a67aee..b5a1464 100644
--- a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-parent-absolute-with-backdrop-filter-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-parent-absolute-with-backdrop-filter-expected.txt
@@ -10,21 +10,22 @@
       "name": "LayoutBlockFlow DIV id='top'",
       "position": [8, 8],
       "bounds": [500, 500],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [485, 485],
-      "shouldFlattenTransform": false
+      "position": [8, 8],
+      "bounds": [485, 485]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [8, 8],
       "bounds": [485, 5000],
       "drawsContent": true
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='middle'",
+      "position": [8, 8],
       "bounds": [400, 400],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -33,6 +34,7 @@
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='child'",
+      "position": [8, 8],
       "bounds": [300, 300],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -42,6 +44,7 @@
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='tall'",
+      "position": [8, 8],
       "bounds": [20, 5000],
       "contentsOpaque": true,
       "drawsContent": true,
@@ -49,21 +52,22 @@
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [8, 8],
       "bounds": [500, 500]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [0, 485],
+      "position": [8, 493],
       "bounds": [485, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [485, 0],
+      "position": [493, 8],
       "bounds": [15, 485]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [485, 485],
+      "position": [493, 493],
       "bounds": [15, 15],
       "drawsContent": true
     }
diff --git a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-parent-with-non-stacking-context-composited-ancestor-expected.txt b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-parent-with-non-stacking-context-composited-ancestor-expected.txt
index 9bbae17c..73f595f3 100644
--- a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-parent-with-non-stacking-context-composited-ancestor-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-parent-with-non-stacking-context-composited-ancestor-expected.txt
@@ -17,18 +17,18 @@
     },
     {
       "name": "LayoutBlockFlow DIV id='scroller'",
+      "position": [98, 90],
       "bounds": [102, 102],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "position": [1, 1],
-      "bounds": [100, 100],
-      "shouldFlattenTransform": false
+      "position": [99, 91],
+      "bounds": [100, 100]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [99, 91],
       "bounds": [100, 180]
     },
     {
@@ -40,8 +40,7 @@
       "backgroundColor": "#008000"
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='scrolled'",
@@ -64,7 +63,7 @@
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [94, 1],
+      "position": [192, 91],
       "bounds": [7, 100]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrolling-content-clip-to-viewport-expected.txt b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrolling-content-clip-to-viewport-expected.txt
index c1c3c456..c5feec6 100644
--- a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrolling-content-clip-to-viewport-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrolling-content-clip-to-viewport-expected.txt
@@ -9,13 +9,11 @@
     {
       "name": "LayoutBlockFlow DIV class='scroller'",
       "bounds": [320, 340],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "bounds": [305, 325],
-      "shouldFlattenTransform": false
+      "bounds": [305, 325]
     },
     {
       "name": "Scrolling Contents Layer",
diff --git a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/universal-accelerated-overflow-scroll-expected.txt b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/universal-accelerated-overflow-scroll-expected.txt
index 150127f9..b5745fc 100644
--- a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/universal-accelerated-overflow-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/universal-accelerated-overflow-scroll-expected.txt
@@ -7,44 +7,43 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow DIV id='container-absolute-grandchildren-not-contained' class='overflow'",
       "position": [10, 10],
       "bounds": [104, 104],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "position": [2, 2],
-      "bounds": [85, 85],
-      "shouldFlattenTransform": false
+      "position": [12, 12],
+      "bounds": [85, 85]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [12, 12],
       "bounds": [85, 144],
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [10, 10],
       "bounds": [104, 104]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [2, 87],
+      "position": [12, 97],
       "bounds": [85, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [87, 2],
+      "position": [97, 12],
       "bounds": [15, 85]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [87, 87],
+      "position": [97, 97],
       "bounds": [15, 15],
       "drawsContent": true
     },
@@ -55,8 +54,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-absolute-grandchildren-not-contained' class='scrolled'",
@@ -76,43 +74,42 @@
       "name": "LayoutBlockFlow (positioned) DIV id='container-absolute-grandchildren' class='positionAbsolute overflow'",
       "position": [130, 10],
       "bounds": [104, 104],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "position": [2, 2],
-      "bounds": [85, 85],
-      "shouldFlattenTransform": false
+      "position": [132, 12],
+      "bounds": [85, 85]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [132, 12],
       "bounds": [105, 144],
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [130, 10],
       "bounds": [104, 104]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [2, 87],
+      "position": [132, 97],
       "bounds": [85, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [87, 2],
+      "position": [217, 12],
       "bounds": [15, 85]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [87, 87],
+      "position": [217, 97],
       "bounds": [15, 15],
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='positioned-absolute-grandchildren' class='positionAbsolute positioned'",
@@ -129,43 +126,42 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow DIV id='container-absolute-not-contained' class='overflow'",
       "position": [250, 10],
       "bounds": [104, 104],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "position": [2, 2],
-      "bounds": [85, 85],
-      "shouldFlattenTransform": false
+      "position": [252, 12],
+      "bounds": [85, 85]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [252, 12],
       "bounds": [85, 144]
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [250, 10],
       "bounds": [104, 104]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [2, 87],
+      "position": [252, 97],
       "bounds": [85, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [87, 2],
+      "position": [337, 12],
       "bounds": [15, 85]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [87, 87],
+      "position": [337, 97],
       "bounds": [15, 15],
       "drawsContent": true
     },
@@ -176,8 +172,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-absolute-not-contained' class='scrolled'",
@@ -194,44 +189,43 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow DIV id='container-absolute-sibling-grandchildren-not-contained' class='overflow'",
       "position": [370, 10],
       "bounds": [104, 104],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "position": [2, 2],
-      "bounds": [85, 85],
-      "shouldFlattenTransform": false
+      "position": [372, 12],
+      "bounds": [85, 85]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [372, 12],
       "bounds": [85, 144],
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [370, 10],
       "bounds": [104, 104]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [2, 87],
+      "position": [372, 97],
       "bounds": [85, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [87, 2],
+      "position": [457, 12],
       "bounds": [15, 85]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [87, 87],
+      "position": [457, 97],
       "bounds": [15, 15],
       "drawsContent": true
     },
@@ -242,8 +236,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-absolute-sibling-grandchildren-not-contained' class='scrolled'",
@@ -263,43 +256,42 @@
       "name": "LayoutBlockFlow (positioned) DIV id='container-absolute-sibling-grandchildren' class='positionAbsolute overflow'",
       "position": [10, 130],
       "bounds": [104, 104],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "position": [2, 2],
-      "bounds": [85, 85],
-      "shouldFlattenTransform": false
+      "position": [12, 132],
+      "bounds": [85, 85]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [12, 132],
       "bounds": [105, 144],
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [10, 130],
       "bounds": [104, 104]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [2, 87],
+      "position": [12, 217],
       "bounds": [85, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [87, 2],
+      "position": [97, 132],
       "bounds": [15, 85]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [87, 87],
+      "position": [97, 217],
       "bounds": [15, 15],
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='positioned-absolute-sibling-grandchildren' class='positionAbsolute positioned'",
@@ -316,43 +308,42 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow DIV id='container-absolute-sibling-not-contained' class='overflow'",
       "position": [130, 130],
       "bounds": [104, 104],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "position": [2, 2],
-      "bounds": [85, 85],
-      "shouldFlattenTransform": false
+      "position": [132, 132],
+      "bounds": [85, 85]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [132, 132],
       "bounds": [85, 144]
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [130, 130],
       "bounds": [104, 104]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [2, 87],
+      "position": [132, 217],
       "bounds": [85, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [87, 2],
+      "position": [217, 132],
       "bounds": [15, 85]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [87, 87],
+      "position": [217, 217],
       "bounds": [15, 15],
       "drawsContent": true
     },
@@ -363,8 +354,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-absolute-sibling-not-contained' class='scrolled'",
@@ -384,42 +374,41 @@
       "name": "LayoutBlockFlow (positioned) DIV id='container-absolute-sibling' class='positionAbsolute overflow'",
       "position": [250, 130],
       "bounds": [104, 104],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "position": [2, 2],
-      "bounds": [85, 85],
-      "shouldFlattenTransform": false
+      "position": [252, 132],
+      "bounds": [85, 85]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [252, 132],
       "bounds": [105, 144]
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [250, 130],
       "bounds": [104, 104]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [2, 87],
+      "position": [252, 217],
       "bounds": [85, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [87, 2],
+      "position": [337, 132],
       "bounds": [15, 85]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [87, 87],
+      "position": [337, 217],
       "bounds": [15, 15],
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='positioned-absolute-sibling' class='positionAbsolute positioned'",
@@ -439,42 +428,41 @@
       "name": "LayoutBlockFlow (positioned) DIV id='container-absolute' class='positionAbsolute overflow'",
       "position": [370, 130],
       "bounds": [104, 104],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "position": [2, 2],
-      "bounds": [85, 85],
-      "shouldFlattenTransform": false
+      "position": [372, 132],
+      "bounds": [85, 85]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [372, 132],
       "bounds": [105, 144]
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [370, 130],
       "bounds": [104, 104]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [2, 87],
+      "position": [372, 217],
       "bounds": [85, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [87, 2],
+      "position": [457, 132],
       "bounds": [15, 85]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [87, 87],
+      "position": [457, 217],
       "bounds": [15, 15],
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='positioned-absolute' class='positionAbsolute positioned'",
@@ -494,37 +482,37 @@
       "name": "LayoutBlockFlow (positioned) DIV id='container-fixed-sibling-grandchildren' class='positionAbsolute overflow'",
       "position": [10, 250],
       "bounds": [104, 104],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "position": [2, 2],
-      "bounds": [85, 85],
-      "shouldFlattenTransform": false
+      "position": [12, 252],
+      "bounds": [85, 85]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [12, 252],
       "bounds": [85, 144],
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [10, 250],
       "bounds": [104, 104]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [2, 87],
+      "position": [12, 337],
       "bounds": [85, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [87, 2],
+      "position": [97, 252],
       "bounds": [15, 85]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [87, 87],
+      "position": [97, 337],
       "bounds": [15, 15],
       "drawsContent": true
     },
@@ -537,8 +525,7 @@
       "backgroundColor": "#800080"
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-fixed-sibling-grandchildren' class='scrolled'",
@@ -558,36 +545,36 @@
       "name": "LayoutBlockFlow (positioned) DIV id='container-fixed-sibling' class='positionAbsolute overflow'",
       "position": [130, 250],
       "bounds": [104, 104],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "position": [2, 2],
-      "bounds": [85, 85],
-      "shouldFlattenTransform": false
+      "position": [132, 252],
+      "bounds": [85, 85]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [132, 252],
       "bounds": [85, 144]
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [130, 250],
       "bounds": [104, 104]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [2, 87],
+      "position": [132, 337],
       "bounds": [85, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [87, 2],
+      "position": [217, 252],
       "bounds": [15, 85]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [87, 87],
+      "position": [217, 337],
       "bounds": [15, 15],
       "drawsContent": true
     },
@@ -600,8 +587,7 @@
       "backgroundColor": "#800080"
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-fixed-sibling' class='scrolled'",
@@ -621,37 +607,37 @@
       "name": "LayoutBlockFlow (positioned) DIV id='container-fixed-grandchildren' class='positionAbsolute overflow'",
       "position": [250, 250],
       "bounds": [104, 104],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "position": [2, 2],
-      "bounds": [85, 85],
-      "shouldFlattenTransform": false
+      "position": [252, 252],
+      "bounds": [85, 85]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [252, 252],
       "bounds": [85, 144],
       "drawsContent": true
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [250, 250],
       "bounds": [104, 104]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [2, 87],
+      "position": [252, 337],
       "bounds": [85, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [87, 2],
+      "position": [337, 252],
       "bounds": [15, 85]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [87, 87],
+      "position": [337, 337],
       "bounds": [15, 15],
       "drawsContent": true
     },
@@ -664,8 +650,7 @@
       "backgroundColor": "#800080"
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-fixed-grandchildren' class='scrolled'",
@@ -685,36 +670,36 @@
       "name": "LayoutBlockFlow (positioned) DIV id='container-fixed' class='positionAbsolute overflow'",
       "position": [370, 250],
       "bounds": [104, 104],
-      "shouldFlattenTransform": false,
       "drawsContent": true
     },
     {
       "name": "Scrolling Layer",
-      "position": [2, 2],
-      "bounds": [85, 85],
-      "shouldFlattenTransform": false
+      "position": [372, 252],
+      "bounds": [85, 85]
     },
     {
       "name": "Scrolling Contents Layer",
+      "position": [372, 252],
       "bounds": [85, 144]
     },
     {
       "name": "Overflow Controls Host Layer",
+      "position": [370, 250],
       "bounds": [104, 104]
     },
     {
       "name": "Horizontal Scrollbar Layer",
-      "position": [2, 87],
+      "position": [372, 337],
       "bounds": [85, 15]
     },
     {
       "name": "Vertical Scrollbar Layer",
-      "position": [87, 2],
+      "position": [457, 252],
       "bounds": [15, 85]
     },
     {
       "name": "Scroll Corner Layer",
-      "position": [87, 87],
+      "position": [457, 337],
       "bounds": [15, 15],
       "drawsContent": true
     },
@@ -727,8 +712,7 @@
       "backgroundColor": "#800080"
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-fixed' class='scrolled'",
@@ -793,8 +777,7 @@
       "backgroundColor": "#008000"
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-absolute-grandchildren-not-contained' class='scrolled onTop'",
@@ -811,8 +794,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-absolute-grandchildren' class='scrolled onTop'",
@@ -829,8 +811,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-absolute-not-contained' class='scrolled onTop'",
@@ -847,8 +828,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-absolute-sibling-grandchildren-not-contained' class='scrolled onTop'",
@@ -865,8 +845,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-absolute-sibling-grandchildren' class='scrolled onTop'",
@@ -883,8 +862,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-absolute-sibling-not-contained' class='scrolled onTop'",
@@ -901,8 +879,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-absolute-sibling' class='scrolled onTop'",
@@ -919,8 +896,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-absolute' class='scrolled onTop'",
@@ -937,8 +913,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-fixed-sibling-grandchildren' class='scrolled onTop'",
@@ -955,8 +930,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-fixed-sibling' class='scrolled onTop'",
@@ -973,8 +947,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-fixed-grandchildren' class='scrolled onTop'",
@@ -991,8 +964,7 @@
       "drawsContent": true
     },
     {
-      "name": "Squashing Containment Layer",
-      "shouldFlattenTransform": false
+      "name": "Squashing Containment Layer"
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='scrolled-fixed' class='scrolled onTop'",
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/inspector/tracing/README.txt b/third_party/WebKit/LayoutTests/virtual/threaded/http/tests/devtools/tracing/README.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/virtual/threaded/inspector/tracing/README.txt
rename to third_party/WebKit/LayoutTests/virtual/threaded/http/tests/devtools/tracing/README.txt
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/inspector/tracing/idle-callback-expected.txt b/third_party/WebKit/LayoutTests/virtual/threaded/http/tests/devtools/tracing/idle-callback-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/virtual/threaded/inspector/tracing/idle-callback-expected.txt
rename to third_party/WebKit/LayoutTests/virtual/threaded/http/tests/devtools/tracing/idle-callback-expected.txt
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/inspector/tracing/idle-callback.html b/third_party/WebKit/LayoutTests/virtual/threaded/http/tests/devtools/tracing/idle-callback.html
similarity index 89%
rename from third_party/WebKit/LayoutTests/virtual/threaded/inspector/tracing/idle-callback.html
rename to third_party/WebKit/LayoutTests/virtual/threaded/http/tests/devtools/tracing/idle-callback.html
index 4d3ce9a..81dda046 100644
--- a/third_party/WebKit/LayoutTests/virtual/threaded/inspector/tracing/idle-callback.html
+++ b/third_party/WebKit/LayoutTests/virtual/threaded/http/tests/devtools/tracing/idle-callback.html
@@ -1,7 +1,7 @@
 <html>
 <head>
-<script src="../../../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../../../http/tests/inspector/timeline-test.js"></script>
+<script src="../../../../../../http/tests/inspector/inspector-test.js"></script>
+<script src="../../../../../../http/tests/inspector/timeline-test.js"></script>
 <script>
 function performActions(idleWarningAddOn)
 {
diff --git a/third_party/WebKit/Source/controller/BlinkInitializer.cpp b/third_party/WebKit/Source/controller/BlinkInitializer.cpp
index 557b1c4..85926b91 100644
--- a/third_party/WebKit/Source/controller/BlinkInitializer.cpp
+++ b/third_party/WebKit/Source/controller/BlinkInitializer.cpp
@@ -30,6 +30,7 @@
 
 #include "bindings/core/v8/V8Initializer.h"
 #include "bindings/modules/v8/V8ContextSnapshotExternalReferences.h"
+#include "build/build_config.h"
 #include "core/animation/AnimationClock.h"
 #include "modules/ModulesInitializer.h"
 #include "platform/bindings/Microtask.h"
@@ -69,8 +70,27 @@
 void Initialize(Platform* platform) {
   Platform::Initialize(platform);
 
+#if !defined(ARCH_CPU_X86_64) && !defined(ARCH_CPU_ARM64) && defined(OS_WIN)
+  // Reserve address space on 32 bit Windows, to make it likelier that large
+  // array buffer allocations succeed.
+  BOOL is_wow_64 = -1;
+  if (!IsWow64Process(GetCurrentProcess(), &is_wow_64))
+    is_wow_64 = FALSE;
+  if (!is_wow_64) {
+    // Try to reserve as much address space as we reasonably can.
+    const size_t kMB = 1024 * 1024;
+    for (size_t size = 512 * kMB; size >= 32 * kMB; size -= 16 * kMB) {
+      if (base::ReserveAddressSpace(size)) {
+        break;
+      }
+    }
+  }
+#endif  // !defined(ARCH_CPU_X86_64) && !defined(ARCH_CPU_ARM64) &&
+        // defined(OS_WIN)
+
   V8Initializer::InitializeMainThread(
       V8ContextSnapshotExternalReferences::GetTable());
+
   GetModulesInitializer().Initialize();
 
   // currentThread is null if we are running on a thread without a message loop.
diff --git a/third_party/WebKit/Source/core/BUILD.gn b/third_party/WebKit/Source/core/BUILD.gn
index 75e38db20e..7b40f91 100644
--- a/third_party/WebKit/Source/core/BUILD.gn
+++ b/third_party/WebKit/Source/core/BUILD.gn
@@ -1429,7 +1429,6 @@
     "html/HTMLEmbedElementTest.cpp",
     "html/HTMLFormControlElementTest.cpp",
     "html/HTMLFrameElementTest.cpp",
-    "html/HTMLIFrameElementAllowTest.cpp",
     "html/HTMLIFrameElementTest.cpp",
     "html/HTMLImageElementTest.cpp",
     "html/HTMLInputElementTest.cpp",
diff --git a/third_party/WebKit/Source/core/css/BUILD.gn b/third_party/WebKit/Source/core/css/BUILD.gn
index 0d23340..4ed138a 100644
--- a/third_party/WebKit/Source/core/css/BUILD.gn
+++ b/third_party/WebKit/Source/core/css/BUILD.gn
@@ -496,6 +496,7 @@
     "properties/CSSPropertyAPITextDecorationColor.cpp",
     "properties/CSSPropertyAPITextDecorationLine.cpp",
     "properties/CSSPropertyAPITextDecorationSkip.cpp",
+    "properties/CSSPropertyAPITextEmphasisPosition.cpp",
     "properties/CSSPropertyAPITextIndent.cpp",
     "properties/CSSPropertyAPITextShadow.cpp",
     "properties/CSSPropertyAPITextSizeAdjust.cpp",
diff --git a/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h b/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h
index 1105f0b..899c8ba 100644
--- a/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h
+++ b/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h
@@ -738,34 +738,6 @@
 }
 
 template <>
-inline CSSIdentifierValue::CSSIdentifierValue(TextEmphasisPosition position)
-    : CSSValue(kIdentifierClass) {
-  switch (position) {
-    case TextEmphasisPosition::kOver:
-      value_id_ = CSSValueOver;
-      break;
-    case TextEmphasisPosition::kUnder:
-      value_id_ = CSSValueUnder;
-      break;
-  }
-}
-
-template <>
-inline TextEmphasisPosition CSSIdentifierValue::ConvertTo() const {
-  switch (value_id_) {
-    case CSSValueOver:
-      return TextEmphasisPosition::kOver;
-    case CSSValueUnder:
-      return TextEmphasisPosition::kUnder;
-    default:
-      break;
-  }
-
-  NOTREACHED();
-  return TextEmphasisPosition::kOver;
-}
-
-template <>
 inline CSSIdentifierValue::CSSIdentifierValue(TextEmphasisFill fill)
     : CSSValue(kIdentifierClass) {
   switch (fill) {
diff --git a/third_party/WebKit/Source/core/css/CSSProperties.json5 b/third_party/WebKit/Source/core/css/CSSProperties.json5
index 23c344c..c5ec3a8a 100644
--- a/third_party/WebKit/Source/core/css/CSSProperties.json5
+++ b/third_party/WebKit/Source/core/css/CSSProperties.json5
@@ -3384,13 +3384,16 @@
     },
     {
       name: "-webkit-text-emphasis-position",
-      api_class: "CSSPropertyAPIInherited",
+      api_class: "CSSPropertyAPITextEmphasisPosition",
+      api_methods: ["ParseSingleValue"],
+      converter: "ConvertTextTextEmphasisPosition",
       inherited: true,
-      field_template: "keyword",
+      field_template: "storage_only",
       type_name: "TextEmphasisPosition",
-      default_value: "over",
-      keywords: ["over", "under"],
+      default_value: "TextEmphasisPosition::kOverRight",
+      field_size: 2,
       field_group: "*",
+      default_generated_functions: ["getter", "setter"],
     },
     {
       name: "-webkit-text-emphasis-style",
diff --git a/third_party/WebKit/Source/core/css/CSSValueKeywords.json5 b/third_party/WebKit/Source/core/css/CSSValueKeywords.json5
index d52fccc6..81cb4e09 100644
--- a/third_party/WebKit/Source/core/css/CSSValueKeywords.json5
+++ b/third_party/WebKit/Source/core/css/CSSValueKeywords.json5
@@ -838,6 +838,8 @@
     // -webkit-text-emphasis-position
     "over",
     "under",
+    //right
+    //left
 
     // -webkit-text-emphasis-style
     "filled",
diff --git a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
index 68bf73ff..8736fc6 100644
--- a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
+++ b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
@@ -2938,8 +2938,28 @@
       return CurrentColorOrValidColor(style, style.TextFillColor());
     case CSSPropertyWebkitTextEmphasisColor:
       return CurrentColorOrValidColor(style, style.TextEmphasisColor());
-    case CSSPropertyWebkitTextEmphasisPosition:
-      return CSSIdentifierValue::Create(style.GetTextEmphasisPosition());
+    case CSSPropertyWebkitTextEmphasisPosition: {
+      CSSValueList* list = CSSValueList::CreateSpaceSeparated();
+      switch (style.GetTextEmphasisPosition()) {
+        case TextEmphasisPosition::kOverRight:
+          list->Append(*CSSIdentifierValue::Create(CSSValueOver));
+          list->Append(*CSSIdentifierValue::Create(CSSValueRight));
+          break;
+        case TextEmphasisPosition::kOverLeft:
+          list->Append(*CSSIdentifierValue::Create(CSSValueOver));
+          list->Append(*CSSIdentifierValue::Create(CSSValueLeft));
+          break;
+        case TextEmphasisPosition::kUnderRight:
+          list->Append(*CSSIdentifierValue::Create(CSSValueUnder));
+          list->Append(*CSSIdentifierValue::Create(CSSValueRight));
+          break;
+        case TextEmphasisPosition::kUnderLeft:
+          list->Append(*CSSIdentifierValue::Create(CSSValueUnder));
+          list->Append(*CSSIdentifierValue::Create(CSSValueLeft));
+          break;
+      }
+      return list;
+    }
     case CSSPropertyWebkitTextEmphasisStyle:
       switch (style.GetTextEmphasisMark()) {
         case TextEmphasisMark::kNone:
diff --git a/third_party/WebKit/Source/core/css/PropertyRegistration.cpp b/third_party/WebKit/Source/core/css/PropertyRegistration.cpp
index da7bb71..329bd37d 100644
--- a/third_party/WebKit/Source/core/css/PropertyRegistration.cpp
+++ b/third_party/WebKit/Source/core/css/PropertyRegistration.cpp
@@ -19,6 +19,7 @@
 #include "core/dom/Document.h"
 #include "core/dom/ExceptionCode.h"
 #include "core/dom/StyleChangeReason.h"
+#include "core/dom/StyleEngine.h"
 
 namespace blink {
 
@@ -147,10 +148,7 @@
                                              descriptor.inherits(), initial,
                                              std::move(initial_variable_data)));
 
-  // TODO(timloh): Invalidate only elements with this custom property set
-  document->SetNeedsStyleRecalc(kSubtreeStyleChange,
-                                StyleChangeReasonForTracing::Create(
-                                    StyleChangeReason::kPropertyRegistration));
+  document->GetStyleEngine().CustomPropertyRegistered();
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/parser/CSSParserFastPaths.cpp b/third_party/WebKit/Source/core/css/parser/CSSParserFastPaths.cpp
index a6a8f98..25f92fa 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSParserFastPaths.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSParserFastPaths.cpp
@@ -820,8 +820,6 @@
       return value_id == CSSValueBefore || value_id == CSSValueAfter;
     case CSSPropertyWebkitTextCombine:
       return value_id == CSSValueNone || value_id == CSSValueHorizontal;
-    case CSSPropertyWebkitTextEmphasisPosition:
-      return value_id == CSSValueOver || value_id == CSSValueUnder;
     case CSSPropertyWebkitTextSecurity:
       return value_id == CSSValueDisc || value_id == CSSValueCircle ||
              value_id == CSSValueSquare || value_id == CSSValueNone;
@@ -964,7 +962,6 @@
     case CSSPropertyWebkitRtlOrdering:
     case CSSPropertyWebkitRubyPosition:
     case CSSPropertyWebkitTextCombine:
-    case CSSPropertyWebkitTextEmphasisPosition:
     case CSSPropertyWebkitTextSecurity:
     case CSSPropertyTransformBox:
     case CSSPropertyTransformStyle:
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITextEmphasisPosition.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITextEmphasisPosition.cpp
new file mode 100644
index 0000000..146d7f1
--- /dev/null
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITextEmphasisPosition.cpp
@@ -0,0 +1,64 @@
+// 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/CSSPropertyAPITextEmphasisPosition.h"
+
+#include "core/css/CSSIdentifierValue.h"
+#include "core/css/CSSValueList.h"
+#include "core/css/parser/CSSPropertyParserHelpers.h"
+
+class CSSParserLocalContext;
+namespace blink {
+
+// [ over | under ] && [ right | left ]?
+// If [ right | left ] is omitted, it defaults to right.
+const CSSValue* CSSPropertyAPITextEmphasisPosition::ParseSingleValue(
+    CSSPropertyID,
+    CSSParserTokenRange& range,
+    const CSSParserContext& context,
+    const CSSParserLocalContext&) const {
+  CSSIdentifierValue* values[2] = {
+      CSSPropertyParserHelpers::ConsumeIdent<CSSValueOver, CSSValueUnder,
+                                             CSSValueRight, CSSValueLeft>(
+          range),
+      nullptr};
+  if (!values[0])
+    return nullptr;
+  values[1] = CSSPropertyParserHelpers::ConsumeIdent<
+      CSSValueOver, CSSValueUnder, CSSValueRight, CSSValueLeft>(range);
+  CSSIdentifierValue* over_under = nullptr;
+  CSSIdentifierValue* left_right = nullptr;
+
+  for (auto value : values) {
+    if (!value)
+      break;
+    switch (value->GetValueID()) {
+      case CSSValueOver:
+      case CSSValueUnder:
+        if (over_under)
+          return nullptr;
+        over_under = value;
+        break;
+      case CSSValueLeft:
+      case CSSValueRight:
+        if (left_right)
+          return nullptr;
+        left_right = value;
+        break;
+      default:
+        NOTREACHED();
+        break;
+    }
+  }
+  if (!over_under)
+    return nullptr;
+  if (!left_right)
+    left_right = CSSIdentifierValue::Create(CSSValueRight);
+  CSSValueList* list = CSSValueList::CreateSpaceSeparated();
+  list->Append(*over_under);
+  list->Append(*left_right);
+  return list;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp b/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp
index 52d94bd..2d841169 100644
--- a/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp
+++ b/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp
@@ -1355,6 +1355,24 @@
       value, Color(), for_visited_link);
 }
 
+TextEmphasisPosition StyleBuilderConverter::ConvertTextTextEmphasisPosition(
+    StyleResolverState& state,
+    const CSSValue& value) {
+  const CSSValueList& list = ToCSSValueList(value);
+  DCHECK(list.Item(0).IsIdentifierValue());
+  DCHECK(list.Item(1).IsIdentifierValue());
+  CSSValueID first = ToCSSIdentifierValue(list.Item(0)).GetValueID();
+  CSSValueID second = ToCSSIdentifierValue(list.Item(1)).GetValueID();
+  if (first == CSSValueOver && second == CSSValueRight)
+    return TextEmphasisPosition::kOverRight;
+  if (first == CSSValueOver && second == CSSValueLeft)
+    return TextEmphasisPosition::kOverLeft;
+  if (first == CSSValueUnder && second == CSSValueRight)
+    return TextEmphasisPosition::kUnderRight;
+  if (first == CSSValueUnder && second == CSSValueLeft)
+    return TextEmphasisPosition::kUnderLeft;
+  return TextEmphasisPosition::kOverRight;
+}
 float StyleBuilderConverter::ConvertTextStrokeWidth(StyleResolverState& state,
                                                     const CSSValue& value) {
   if (value.IsIdentifierValue() && ToCSSIdentifierValue(value).GetValueID()) {
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.h b/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.h
index df8e0f4..cc80c649 100644
--- a/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.h
+++ b/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.h
@@ -177,6 +177,9 @@
   static StyleAutoColor ConvertStyleAutoColor(StyleResolverState&,
                                               const CSSValue&,
                                               bool for_visited_link = false);
+  static TextEmphasisPosition ConvertTextTextEmphasisPosition(
+      StyleResolverState&,
+      const CSSValue&);
   static float ConvertTextStrokeWidth(StyleResolverState&, const CSSValue&);
   static TextSizeAdjust ConvertTextSizeAdjust(StyleResolverState&,
                                               const CSSValue&);
diff --git a/third_party/WebKit/Source/core/dom/AXObjectCache.cpp b/third_party/WebKit/Source/core/dom/AXObjectCache.cpp
index 47c3e00..d7ad4864 100644
--- a/third_party/WebKit/Source/core/dom/AXObjectCache.cpp
+++ b/third_party/WebKit/Source/core/dom/AXObjectCache.cpp
@@ -54,7 +54,8 @@
   return create_function_(document);
 }
 
-AXObjectCache::AXObjectCache() {}
+AXObjectCache::AXObjectCache(Document& document)
+    : ContextLifecycleObserver(document.GetExecutionContext()) {}
 
 AXObjectCache::~AXObjectCache() {}
 
@@ -165,6 +166,10 @@
   return false;
 }
 
+DEFINE_TRACE(AXObjectCache) {
+  ContextLifecycleObserver::Trace(visitor);
+}
+
 STATIC_ASSERT_ENUM(kWebAXEventActiveDescendantChanged,
                    AXObjectCache::kAXActiveDescendantChanged);
 STATIC_ASSERT_ENUM(kWebAXEventAlert, AXObjectCache::kAXAlert);
diff --git a/third_party/WebKit/Source/core/dom/AXObjectCache.h b/third_party/WebKit/Source/core/dom/AXObjectCache.h
index e4d3f8d3..5f1a606c 100644
--- a/third_party/WebKit/Source/core/dom/AXObjectCache.h
+++ b/third_party/WebKit/Source/core/dom/AXObjectCache.h
@@ -44,14 +44,16 @@
 class LocalFrameView;
 
 class CORE_EXPORT AXObjectCache
-    : public GarbageCollectedFinalized<AXObjectCache> {
+    : public GarbageCollectedFinalized<AXObjectCache>,
+      public ContextLifecycleObserver {
   WTF_MAKE_NONCOPYABLE(AXObjectCache);
+  USING_GARBAGE_COLLECTED_MIXIN(AXObjectCache);
 
  public:
   static AXObjectCache* Create(Document&);
 
   virtual ~AXObjectCache();
-  DEFINE_INLINE_VIRTUAL_TRACE() {}
+  DECLARE_VIRTUAL_TRACE();
 
   enum AXNotification {
     kAXActiveDescendantChanged,
@@ -156,7 +158,7 @@
   static bool IsInsideFocusableElementOrARIAWidget(const Node&);
 
  protected:
-  AXObjectCache();
+  AXObjectCache(Document&);
 
  private:
   static AXObjectCacheCreateFunction create_function_;
diff --git a/third_party/WebKit/Source/core/dom/AXObjectCacheBase.cpp b/third_party/WebKit/Source/core/dom/AXObjectCacheBase.cpp
index 3f1c1bd..0cb3def 100644
--- a/third_party/WebKit/Source/core/dom/AXObjectCacheBase.cpp
+++ b/third_party/WebKit/Source/core/dom/AXObjectCacheBase.cpp
@@ -11,6 +11,7 @@
 
 AXObjectCacheBase::~AXObjectCacheBase() {}
 
-AXObjectCacheBase::AXObjectCacheBase() {}
+AXObjectCacheBase::AXObjectCacheBase(Document& document)
+    : AXObjectCache(document) {}
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/dom/AXObjectCacheBase.h b/third_party/WebKit/Source/core/dom/AXObjectCacheBase.h
index f1c119f..f22da5f 100644
--- a/third_party/WebKit/Source/core/dom/AXObjectCacheBase.h
+++ b/third_party/WebKit/Source/core/dom/AXObjectCacheBase.h
@@ -30,7 +30,7 @@
   virtual AXObject* GetOrCreate(LayoutObject*) = 0;
 
  protected:
-  AXObjectCacheBase();
+  AXObjectCacheBase(Document&);
 };
 
 // This is the only subclass of AXObjectCache.
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index 56622cc..f85bd69 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -5804,8 +5804,8 @@
   WebFeaturePolicy* parent_feature_policy = nullptr;
   WebParsedFeaturePolicy container_policy;
   Vector<String> messages;
-  const WebParsedFeaturePolicy& parsed_header =
-      ParseFeaturePolicy(feature_policy_header, GetSecurityOrigin(), &messages);
+  const WebParsedFeaturePolicy& parsed_header = ParseFeaturePolicyHeader(
+      feature_policy_header, GetSecurityOrigin(), &messages);
 
   // If this frame is not the main frame, then get the appropriate parent policy
   // and container policy to construct the policy for this frame.
diff --git a/third_party/WebKit/Source/core/dom/StyleEngine.cpp b/third_party/WebKit/Source/core/dom/StyleEngine.cpp
index 9830a29..65b64eb 100644
--- a/third_party/WebKit/Source/core/dom/StyleEngine.cpp
+++ b/third_party/WebKit/Source/core/dom/StyleEngine.cpp
@@ -1222,6 +1222,15 @@
   return false;
 }
 
+void StyleEngine::CustomPropertyRegistered() {
+  // TODO(timloh): Invalidate only elements with this custom property set
+  GetDocument().SetNeedsStyleRecalc(
+      kSubtreeStyleChange, StyleChangeReasonForTracing::Create(
+                               StyleChangeReason::kPropertyRegistration));
+  if (resolver_)
+    resolver_->InvalidateMatchedPropertiesCache();
+}
+
 DEFINE_TRACE(StyleEngine) {
   visitor->Trace(document_);
   visitor->Trace(injected_author_style_sheets_);
diff --git a/third_party/WebKit/Source/core/dom/StyleEngine.h b/third_party/WebKit/Source/core/dom/StyleEngine.h
index 8192a45..9fbcbac4 100644
--- a/third_party/WebKit/Source/core/dom/StyleEngine.h
+++ b/third_party/WebKit/Source/core/dom/StyleEngine.h
@@ -273,6 +273,8 @@
                            const ActiveStyleSheetVector& old_style_sheets,
                            const ActiveStyleSheetVector& new_style_sheets);
 
+  void CustomPropertyRegistered();
+
   DECLARE_VIRTUAL_TRACE();
   DECLARE_TRACE_WRAPPERS();
 
diff --git a/third_party/WebKit/Source/core/editing/SurroundingText.cpp b/third_party/WebKit/Source/core/editing/SurroundingText.cpp
index 0d17334..2a3573b 100644
--- a/third_party/WebKit/Source/core/editing/SurroundingText.cpp
+++ b/third_party/WebKit/Source/core/editing/SurroundingText.cpp
@@ -88,8 +88,9 @@
   // starts at the document's or input element's start and ends at the selection
   // start and will be updated.
   BackwardsCharacterIterator backwards_iterator(
-      Position::FirstPositionInNode(*root_element).ParentAnchoredEquivalent(),
-      start_position,
+      EphemeralRange(Position::FirstPositionInNode(*root_element)
+                         .ParentAnchoredEquivalent(),
+                     start_position),
       TextIteratorBehavior::Builder().SetStopsOnFormControls(true).Build());
   if (!backwards_iterator.AtEnd())
     backwards_iterator.Advance(half_max_length);
diff --git a/third_party/WebKit/Source/core/editing/VisibleUnits.cpp b/third_party/WebKit/Source/core/editing/VisibleUnits.cpp
index 6f6c0fb..1004b72a 100644
--- a/third_party/WebKit/Source/core/editing/VisibleUnits.cpp
+++ b/third_party/WebKit/Source/core/editing/VisibleUnits.cpp
@@ -392,7 +392,8 @@
 
   // Use the character iterator to translate the next value into a DOM
   // position.
-  BackwardsCharacterIteratorAlgorithm<Strategy> char_it(start, end);
+  BackwardsCharacterIteratorAlgorithm<Strategy> char_it(
+      EphemeralRangeTemplate<Strategy>(start, end));
   char_it.Advance(string.Size() - suffix_length - next);
   // TODO(yosin) charIt can get out of shadow host.
   return char_it.EndPosition();
diff --git a/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp b/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp
index 95232445..8d73864 100644
--- a/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp
@@ -1072,11 +1072,19 @@
   // Inserting default paragraph element can change visible position. We
   // should update visible positions before use them.
   GetDocument().UpdateStyleAndLayoutIgnorePendingStylesheets();
+  const VisiblePosition& destination =
+      VisiblePosition::FirstPositionInNode(*new_block);
+  if (destination.IsNull()) {
+    // Reached by CompositeEditingCommandTest
+    //    .MoveParagraphContentsToNewBlockWithNonEditableStyle.
+    editing_state->Abort();
+    return nullptr;
+  }
+
   visible_pos = CreateVisiblePosition(pos, VP_DEFAULT_AFFINITY);
   visible_paragraph_start = StartOfParagraph(visible_pos);
   visible_paragraph_end = EndOfParagraph(visible_pos);
-  MoveParagraphs(visible_paragraph_start, visible_paragraph_end,
-                 VisiblePosition::FirstPositionInNode(*new_block),
+  MoveParagraphs(visible_paragraph_start, visible_paragraph_end, destination,
                  editing_state);
   if (editing_state->IsAborted())
     return nullptr;
@@ -1364,6 +1372,10 @@
     ShouldPreserveStyle should_preserve_style,
     Node* constraining_ancestor) {
   DCHECK(!GetDocument().NeedsLayoutTreeUpdate());
+  DCHECK(start_of_paragraph_to_move.IsNotNull());
+  DCHECK(end_of_paragraph_to_move.IsNotNull());
+  DCHECK(destination.IsNotNull());
+
   if (start_of_paragraph_to_move.DeepEquivalent() ==
           destination.DeepEquivalent() ||
       start_of_paragraph_to_move.IsNull())
diff --git a/third_party/WebKit/Source/core/editing/commands/CompositeEditCommandTest.cpp b/third_party/WebKit/Source/core/editing/commands/CompositeEditCommandTest.cpp
index fe6e505..1f1ac78 100644
--- a/third_party/WebKit/Source/core/editing/commands/CompositeEditCommandTest.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/CompositeEditCommandTest.cpp
@@ -24,6 +24,9 @@
                         ShouldAssumeContentIsAlwaysEditable =
                             kDoNotAssumeContentIsAlwaysEditable);
 
+  void MoveParagraphContentsToNewBlockIfNecessary(const Position&,
+                                                  EditingState*);
+
   // CompositeEditCommand member implementations
   void DoApply(EditingState*) final {}
   InputEvent::InputType GetInputType() const final {
@@ -45,6 +48,13 @@
       should_assume_content_is_always_editable);
 }
 
+void SampleCommand::MoveParagraphContentsToNewBlockIfNecessary(
+    const Position& position,
+    EditingState* editing_state) {
+  CompositeEditCommand::MoveParagraphContentsToNewBlockIfNecessary(
+      position, editing_state);
+}
+
 }  // namespace
 
 class CompositeEditCommandTest : public EditingTestBase {};
@@ -102,4 +112,26 @@
   EXPECT_EQ("foo<b></b>", div->innerHTML());
 }
 
+TEST_F(CompositeEditCommandTest,
+       MoveParagraphContentsToNewBlockWithNonEditableStyle) {
+  SetBodyContent(
+      "<style>div{-webkit-user-modify:read-only;user-select:none;}</style>"
+      "foo");
+  SampleCommand& sample = *new SampleCommand(GetDocument());
+  Element* body = GetDocument().body();
+  Node* text = body->lastChild();
+  body->setAttribute(HTMLNames::contenteditableAttr, "true");
+  GetDocument().UpdateStyleAndLayout();
+
+  EditingState editing_state;
+  sample.MoveParagraphContentsToNewBlockIfNecessary(Position(text, 0),
+                                                    &editing_state);
+  EXPECT_TRUE(editing_state.IsAborted());
+  EXPECT_EQ(
+      "<div><br></div>"
+      "<style>div{-webkit-user-modify:read-only;user-select:none;}</style>"
+      "foo",
+      body->innerHTML());
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/iterators/BackwardsCharacterIterator.cpp b/third_party/WebKit/Source/core/editing/iterators/BackwardsCharacterIterator.cpp
index 6758fba..765c471 100644
--- a/third_party/WebKit/Source/core/editing/iterators/BackwardsCharacterIterator.cpp
+++ b/third_party/WebKit/Source/core/editing/iterators/BackwardsCharacterIterator.cpp
@@ -31,13 +31,13 @@
 
 template <typename Strategy>
 BackwardsCharacterIteratorAlgorithm<Strategy>::
-    BackwardsCharacterIteratorAlgorithm(const PositionTemplate<Strategy>& start,
-                                        const PositionTemplate<Strategy>& end,
-                                        const TextIteratorBehavior& behavior)
+    BackwardsCharacterIteratorAlgorithm(
+        const EphemeralRangeTemplate<Strategy>& range,
+        const TextIteratorBehavior& behavior)
     : offset_(0),
       run_offset_(0),
       at_break_(true),
-      text_iterator_(start, end, behavior) {
+      text_iterator_(range.StartPosition(), range.EndPosition(), behavior) {
   while (!AtEnd() && !text_iterator_.length())
     text_iterator_.Advance();
 }
diff --git a/third_party/WebKit/Source/core/editing/iterators/BackwardsCharacterIterator.h b/third_party/WebKit/Source/core/editing/iterators/BackwardsCharacterIterator.h
index 2752732..a64b432 100644
--- a/third_party/WebKit/Source/core/editing/iterators/BackwardsCharacterIterator.h
+++ b/third_party/WebKit/Source/core/editing/iterators/BackwardsCharacterIterator.h
@@ -26,6 +26,7 @@
 #ifndef BackwardsCharacterIterator_h
 #define BackwardsCharacterIterator_h
 
+#include "core/editing/EphemeralRange.h"
 #include "core/editing/iterators/SimplifiedBackwardsTextIterator.h"
 #include "platform/heap/Heap.h"
 
@@ -37,8 +38,7 @@
 
  public:
   BackwardsCharacterIteratorAlgorithm(
-      const PositionTemplate<Strategy>&,
-      const PositionTemplate<Strategy>&,
+      const EphemeralRangeTemplate<Strategy>&,
       const TextIteratorBehavior& = TextIteratorBehavior());
 
   void Advance(int);
diff --git a/third_party/WebKit/Source/core/editing/markers/SuggestionMarkerListImpl.cpp b/third_party/WebKit/Source/core/editing/markers/SuggestionMarkerListImpl.cpp
index 419bda24..2574086 100644
--- a/third_party/WebKit/Source/core/editing/markers/SuggestionMarkerListImpl.cpp
+++ b/third_party/WebKit/Source/core/editing/markers/SuggestionMarkerListImpl.cpp
@@ -4,9 +4,9 @@
 
 #include "core/editing/markers/SuggestionMarkerListImpl.h"
 
-#include "core/editing/markers/SortedDocumentMarkerListEditor.h"
 #include "core/editing/markers/SuggestionMarker.h"
 #include "core/editing/markers/SuggestionMarkerReplacementScope.h"
+#include "core/editing/markers/UnsortedDocumentMarkerListEditor.h"
 
 namespace blink {
 
@@ -78,16 +78,25 @@
 DocumentMarker* SuggestionMarkerListImpl::FirstMarkerIntersectingRange(
     unsigned start_offset,
     unsigned end_offset) const {
+  return UnsortedDocumentMarkerListEditor::FirstMarkerIntersectingRange(
+      markers_, start_offset, end_offset);
+}
+
+// TODO(rlanday): move to UnsortedDocumentMarkerListEditor.cpp.
+DocumentMarker* UnsortedDocumentMarkerListEditor::FirstMarkerIntersectingRange(
+    const MarkerList& list,
+    unsigned start_offset,
+    unsigned end_offset) {
   DCHECK_LE(start_offset, end_offset);
 
   const auto it =
-      std::find_if(markers_.begin(), markers_.end(),
+      std::find_if(list.begin(), list.end(),
                    [start_offset, end_offset](const DocumentMarker* marker) {
                      return marker->StartOffset() < end_offset &&
                             marker->EndOffset() > start_offset;
                    });
 
-  if (it == markers_.end())
+  if (it == list.end())
     return nullptr;
   return *it;
 }
@@ -95,10 +104,20 @@
 HeapVector<Member<DocumentMarker>>
 SuggestionMarkerListImpl::MarkersIntersectingRange(unsigned start_offset,
                                                    unsigned end_offset) const {
+  return UnsortedDocumentMarkerListEditor::MarkersIntersectingRange(
+      markers_, start_offset, end_offset);
+}
+
+// TODO(rlanday): move to UnsortedDocumentMarkerListEditor.cpp.
+HeapVector<Member<DocumentMarker>>
+UnsortedDocumentMarkerListEditor::MarkersIntersectingRange(
+    const MarkerList& list,
+    unsigned start_offset,
+    unsigned end_offset) {
   DCHECK_LE(start_offset, end_offset);
 
   HeapVector<Member<DocumentMarker>> results;
-  std::copy_if(markers_.begin(), markers_.end(), std::back_inserter(results),
+  std::copy_if(list.begin(), list.end(), std::back_inserter(results),
                [start_offset, end_offset](const DocumentMarker* marker) {
                  return marker->StartOffset() < end_offset &&
                         marker->EndOffset() > start_offset;
@@ -108,20 +127,29 @@
 
 bool SuggestionMarkerListImpl::MoveMarkers(int length,
                                            DocumentMarkerList* dst_list) {
+  return UnsortedDocumentMarkerListEditor::MoveMarkers(&markers_, length,
+                                                       dst_list);
+}
+
+// TODO(rlanday): move to UnsortedDocumentMarkerListEditor.cpp.
+bool UnsortedDocumentMarkerListEditor::MoveMarkers(
+    MarkerList* src_list,
+    int length,
+    DocumentMarkerList* dst_list) {
   DCHECK_GT(length, 0);
   bool did_move_marker = false;
   unsigned end_offset = length - 1;
 
   HeapVector<Member<DocumentMarker>> unmoved_markers;
-  for (auto it = markers_.begin(); it != markers_.end(); ++it) {
+  for (auto it = src_list->begin(); it != src_list->end(); ++it) {
     DocumentMarker& marker = **it;
     if (marker.StartOffset() > end_offset) {
       unmoved_markers.push_back(marker);
       continue;
     }
 
-    // If we're splitting a text node in the middle of a suggestion marker,
-    // remove the marker
+    // If we're splitting a text node in the middle of a marker, remove the
+    // marker.
     if (marker.EndOffset() > end_offset)
       continue;
 
@@ -129,18 +157,25 @@
     did_move_marker = true;
   }
 
-  markers_ = std::move(unmoved_markers);
+  *src_list = std::move(unmoved_markers);
   return did_move_marker;
 }
 
 bool SuggestionMarkerListImpl::RemoveMarkers(unsigned start_offset,
                                              int length) {
-  // Since suggestion markers are stored unsorted, the quickest way to perform
-  // this operation is to build a new list with the markers that aren't being
-  // removed.
+  return UnsortedDocumentMarkerListEditor::RemoveMarkers(&markers_,
+                                                         start_offset, length);
+}
+
+// TODO(rlanday): move to UnsortedDocumentMarkerListEditor.cpp.
+bool UnsortedDocumentMarkerListEditor::RemoveMarkers(MarkerList* list,
+                                                     unsigned start_offset,
+                                                     int length) {
+  // For an unsorted marker list, the quickest way to perform this operation is
+  // to build a new list with the markers that aren't being removed.
   const unsigned end_offset = start_offset + length;
   HeapVector<Member<DocumentMarker>> unremoved_markers;
-  for (const Member<DocumentMarker>& marker : markers_) {
+  for (const Member<DocumentMarker>& marker : *list) {
     if (marker->EndOffset() <= start_offset ||
         marker->StartOffset() >= end_offset) {
       unremoved_markers.push_back(marker);
@@ -148,8 +183,8 @@
     }
   }
 
-  const bool did_remove_marker = (unremoved_markers.size() != markers_.size());
-  markers_ = std::move(unremoved_markers);
+  const bool did_remove_marker = (unremoved_markers.size() != list->size());
+  *list = std::move(unremoved_markers);
   return did_remove_marker;
 }
 
diff --git a/third_party/WebKit/Source/core/editing/markers/SuggestionMarkerListImplTest.cpp b/third_party/WebKit/Source/core/editing/markers/SuggestionMarkerListImplTest.cpp
index 6a01fd1f..00b7e2f5 100644
--- a/third_party/WebKit/Source/core/editing/markers/SuggestionMarkerListImplTest.cpp
+++ b/third_party/WebKit/Source/core/editing/markers/SuggestionMarkerListImplTest.cpp
@@ -6,6 +6,7 @@
 
 #include "core/editing/markers/SuggestionMarker.h"
 #include "core/editing/markers/SuggestionMarkerReplacementScope.h"
+#include "core/editing/markers/UnsortedDocumentMarkerListEditor.h"
 #include "platform/heap/Handle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -26,6 +27,19 @@
   Persistent<SuggestionMarkerListImpl> marker_list_;
 };
 
+// TODO(rlanday): split UnsortedDocumentMarkerListEditorTest into its own file.
+class UnsortedDocumentMarkerListEditorTest : public ::testing::Test {
+ protected:
+  DocumentMarker* CreateMarker(unsigned start_offset, unsigned end_offset) {
+    return new SuggestionMarker(start_offset, end_offset, Vector<String>(),
+                                Color::kTransparent, Color::kTransparent,
+                                StyleableMarker::Thickness::kThin,
+                                Color::kTransparent);
+  }
+
+  PersistentHeapVector<Member<DocumentMarker>> marker_list_;
+};
+
 namespace {
 
 bool compare_markers(const Member<DocumentMarker>& marker1,
@@ -91,42 +105,52 @@
   EXPECT_EQ(50u, markers[9]->EndOffset());
 }
 
-TEST_F(SuggestionMarkerListImplTest, FirstMarkerIntersectingRange_Empty) {
-  DocumentMarker* marker = marker_list_->FirstMarkerIntersectingRange(0, 10);
+TEST_F(UnsortedDocumentMarkerListEditorTest,
+       FirstMarkerIntersectingRange_Empty) {
+  DocumentMarker* marker =
+      UnsortedDocumentMarkerListEditor::FirstMarkerIntersectingRange(
+          marker_list_, 0, 10);
   EXPECT_EQ(nullptr, marker);
 }
 
-TEST_F(SuggestionMarkerListImplTest,
+TEST_F(UnsortedDocumentMarkerListEditorTest,
        FirstMarkerIntersectingRange_TouchingStart) {
-  marker_list_->Add(CreateMarker(1, 10));
-  marker_list_->Add(CreateMarker(0, 10));
+  marker_list_.push_back(CreateMarker(1, 10));
+  marker_list_.push_back(CreateMarker(0, 10));
 
-  DocumentMarker* marker = marker_list_->FirstMarkerIntersectingRange(0, 1);
+  DocumentMarker* marker =
+      UnsortedDocumentMarkerListEditor::FirstMarkerIntersectingRange(
+          marker_list_, 0, 1);
 
   EXPECT_NE(nullptr, marker);
   EXPECT_EQ(0u, marker->StartOffset());
   EXPECT_EQ(10u, marker->EndOffset());
 }
 
-TEST_F(SuggestionMarkerListImplTest, FirstMarkerIntersectingRange_TouchingEnd) {
-  marker_list_->Add(CreateMarker(0, 9));
-  marker_list_->Add(CreateMarker(0, 10));
+TEST_F(UnsortedDocumentMarkerListEditorTest,
+       FirstMarkerIntersectingRange_TouchingEnd) {
+  marker_list_.push_back(CreateMarker(0, 9));
+  marker_list_.push_back(CreateMarker(0, 10));
 
-  DocumentMarker* marker = marker_list_->FirstMarkerIntersectingRange(9, 10);
+  DocumentMarker* marker =
+      UnsortedDocumentMarkerListEditor::FirstMarkerIntersectingRange(
+          marker_list_, 9, 10);
 
   EXPECT_NE(nullptr, marker);
   EXPECT_EQ(0u, marker->StartOffset());
   EXPECT_EQ(10u, marker->EndOffset());
 }
 
-TEST_F(SuggestionMarkerListImplTest, MarkersIntersectingRange_TouchingStart) {
-  marker_list_->Add(CreateMarker(0, 9));
-  marker_list_->Add(CreateMarker(1, 9));
-  marker_list_->Add(CreateMarker(0, 10));
-  marker_list_->Add(CreateMarker(1, 10));
+TEST_F(UnsortedDocumentMarkerListEditorTest,
+       MarkersIntersectingRange_TouchingStart) {
+  marker_list_.push_back(CreateMarker(0, 9));
+  marker_list_.push_back(CreateMarker(1, 9));
+  marker_list_.push_back(CreateMarker(0, 10));
+  marker_list_.push_back(CreateMarker(1, 10));
 
-  DocumentMarkerVector markers_intersecting_range =
-      marker_list_->MarkersIntersectingRange(0, 1);
+  UnsortedDocumentMarkerListEditor::MarkerList markers_intersecting_range =
+      UnsortedDocumentMarkerListEditor::MarkersIntersectingRange(marker_list_,
+                                                                 0, 1);
 
   EXPECT_EQ(2u, markers_intersecting_range.size());
 
@@ -137,14 +161,16 @@
   EXPECT_EQ(10u, markers_intersecting_range[1]->EndOffset());
 }
 
-TEST_F(SuggestionMarkerListImplTest, MarkersIntersectingRange_TouchingEnd) {
-  marker_list_->Add(CreateMarker(0, 9));
-  marker_list_->Add(CreateMarker(1, 9));
-  marker_list_->Add(CreateMarker(0, 10));
-  marker_list_->Add(CreateMarker(1, 10));
+TEST_F(UnsortedDocumentMarkerListEditorTest,
+       MarkersIntersectingRange_TouchingEnd) {
+  marker_list_.push_back(CreateMarker(0, 9));
+  marker_list_.push_back(CreateMarker(1, 9));
+  marker_list_.push_back(CreateMarker(0, 10));
+  marker_list_.push_back(CreateMarker(1, 10));
 
-  DocumentMarkerVector markers_intersecting_range =
-      marker_list_->MarkersIntersectingRange(9, 10);
+  UnsortedDocumentMarkerListEditor::MarkerList markers_intersecting_range =
+      UnsortedDocumentMarkerListEditor::MarkersIntersectingRange(marker_list_,
+                                                                 9, 10);
 
   EXPECT_EQ(2u, markers_intersecting_range.size());
 
@@ -155,42 +181,40 @@
   EXPECT_EQ(10u, markers_intersecting_range[1]->EndOffset());
 }
 
-TEST_F(SuggestionMarkerListImplTest, MoveMarkers) {
-  marker_list_->Add(CreateMarker(30, 40));
-  marker_list_->Add(CreateMarker(0, 30));
-  marker_list_->Add(CreateMarker(10, 40));
-  marker_list_->Add(CreateMarker(0, 20));
-  marker_list_->Add(CreateMarker(0, 40));
-  marker_list_->Add(CreateMarker(20, 40));
-  marker_list_->Add(CreateMarker(20, 30));
-  marker_list_->Add(CreateMarker(0, 10));
-  marker_list_->Add(CreateMarker(10, 30));
-  marker_list_->Add(CreateMarker(10, 20));
-  marker_list_->Add(CreateMarker(11, 21));
+TEST_F(UnsortedDocumentMarkerListEditorTest, MoveMarkers) {
+  marker_list_.push_back(CreateMarker(30, 40));
+  marker_list_.push_back(CreateMarker(0, 30));
+  marker_list_.push_back(CreateMarker(10, 40));
+  marker_list_.push_back(CreateMarker(0, 20));
+  marker_list_.push_back(CreateMarker(0, 40));
+  marker_list_.push_back(CreateMarker(20, 40));
+  marker_list_.push_back(CreateMarker(20, 30));
+  marker_list_.push_back(CreateMarker(0, 10));
+  marker_list_.push_back(CreateMarker(10, 30));
+  marker_list_.push_back(CreateMarker(10, 20));
+  marker_list_.push_back(CreateMarker(11, 21));
 
   DocumentMarkerList* dst_list = new SuggestionMarkerListImpl();
   // The markers with start and end offset < 11 should be moved to dst_list.
   // Markers that start before 11 and end at 11 or later should be removed.
   // Markers that start at 11 or later should not be moved.
-  marker_list_->MoveMarkers(11, dst_list);
+  UnsortedDocumentMarkerListEditor::MoveMarkers(&marker_list_, 11, dst_list);
 
-  DocumentMarkerVector source_list_markers = marker_list_->GetMarkers();
-  std::sort(source_list_markers.begin(), source_list_markers.end(),
-            compare_markers);
+  std::sort(marker_list_.begin(), marker_list_.end(), compare_markers);
 
-  EXPECT_EQ(4u, source_list_markers.size());
+  EXPECT_EQ(4u, marker_list_.size());
 
-  EXPECT_EQ(11u, source_list_markers[0]->StartOffset());
-  EXPECT_EQ(21u, source_list_markers[0]->EndOffset());
+  EXPECT_EQ(11u, marker_list_[0]->StartOffset());
+  EXPECT_EQ(21u, marker_list_[0]->EndOffset());
 
-  EXPECT_EQ(20u, source_list_markers[1]->StartOffset());
-  EXPECT_EQ(30u, source_list_markers[1]->EndOffset());
+  EXPECT_EQ(20u, marker_list_[1]->StartOffset());
+  EXPECT_EQ(30u, marker_list_[1]->EndOffset());
 
-  EXPECT_EQ(20u, source_list_markers[2]->StartOffset());
-  EXPECT_EQ(40u, source_list_markers[2]->EndOffset());
+  EXPECT_EQ(20u, marker_list_[2]->StartOffset());
+  EXPECT_EQ(40u, marker_list_[2]->EndOffset());
 
-  EXPECT_EQ(30u, source_list_markers[3]->StartOffset());
-  EXPECT_EQ(40u, source_list_markers[3]->EndOffset());
+  EXPECT_EQ(30u, marker_list_[3]->StartOffset());
+  EXPECT_EQ(40u, marker_list_[3]->EndOffset());
 
   DocumentMarkerVector dst_list_markers = dst_list->GetMarkers();
   std::sort(dst_list_markers.begin(), dst_list_markers.end(), compare_markers);
@@ -202,57 +226,59 @@
   EXPECT_EQ(10u, dst_list_markers[0]->EndOffset());
 }
 
-TEST_F(SuggestionMarkerListImplTest, RemoveMarkersEmptyList) {
-  EXPECT_FALSE(marker_list_->RemoveMarkers(0, 10));
-  EXPECT_EQ(0u, marker_list_->GetMarkers().size());
+TEST_F(UnsortedDocumentMarkerListEditorTest, RemoveMarkersEmptyList) {
+  EXPECT_FALSE(
+      UnsortedDocumentMarkerListEditor::RemoveMarkers(&marker_list_, 0, 10));
+  EXPECT_EQ(0u, marker_list_.size());
 }
 
-TEST_F(SuggestionMarkerListImplTest, RemoveMarkersTouchingEndpoints) {
-  marker_list_->Add(CreateMarker(30, 40));
-  marker_list_->Add(CreateMarker(40, 50));
-  marker_list_->Add(CreateMarker(10, 20));
-  marker_list_->Add(CreateMarker(0, 10));
-  marker_list_->Add(CreateMarker(20, 30));
+TEST_F(UnsortedDocumentMarkerListEditorTest, RemoveMarkersTouchingEndpoints) {
+  marker_list_.push_back(CreateMarker(30, 40));
+  marker_list_.push_back(CreateMarker(40, 50));
+  marker_list_.push_back(CreateMarker(10, 20));
+  marker_list_.push_back(CreateMarker(0, 10));
+  marker_list_.push_back(CreateMarker(20, 30));
 
-  EXPECT_TRUE(marker_list_->RemoveMarkers(20, 10));
+  EXPECT_TRUE(
+      UnsortedDocumentMarkerListEditor::RemoveMarkers(&marker_list_, 20, 10));
 
-  DocumentMarkerVector markers = marker_list_->GetMarkers();
-  std::sort(markers.begin(), markers.end(), compare_markers);
+  std::sort(marker_list_.begin(), marker_list_.end(), compare_markers);
 
-  EXPECT_EQ(4u, markers.size());
+  EXPECT_EQ(4u, marker_list_.size());
 
-  EXPECT_EQ(0u, markers[0]->StartOffset());
-  EXPECT_EQ(10u, markers[0]->EndOffset());
+  EXPECT_EQ(0u, marker_list_[0]->StartOffset());
+  EXPECT_EQ(10u, marker_list_[0]->EndOffset());
 
-  EXPECT_EQ(10u, markers[1]->StartOffset());
-  EXPECT_EQ(20u, markers[1]->EndOffset());
+  EXPECT_EQ(10u, marker_list_[1]->StartOffset());
+  EXPECT_EQ(20u, marker_list_[1]->EndOffset());
 
-  EXPECT_EQ(30u, markers[2]->StartOffset());
-  EXPECT_EQ(40u, markers[2]->EndOffset());
+  EXPECT_EQ(30u, marker_list_[2]->StartOffset());
+  EXPECT_EQ(40u, marker_list_[2]->EndOffset());
 
-  EXPECT_EQ(40u, markers[3]->StartOffset());
-  EXPECT_EQ(50u, markers[3]->EndOffset());
+  EXPECT_EQ(40u, marker_list_[3]->StartOffset());
+  EXPECT_EQ(50u, marker_list_[3]->EndOffset());
 }
 
-TEST_F(SuggestionMarkerListImplTest, RemoveMarkersOneCharacterIntoInterior) {
-  marker_list_->Add(CreateMarker(30, 40));
-  marker_list_->Add(CreateMarker(40, 50));
-  marker_list_->Add(CreateMarker(10, 20));
-  marker_list_->Add(CreateMarker(0, 10));
-  marker_list_->Add(CreateMarker(20, 30));
+TEST_F(UnsortedDocumentMarkerListEditorTest,
+       RemoveMarkersOneCharacterIntoInterior) {
+  marker_list_.push_back(CreateMarker(30, 40));
+  marker_list_.push_back(CreateMarker(40, 50));
+  marker_list_.push_back(CreateMarker(10, 20));
+  marker_list_.push_back(CreateMarker(0, 10));
+  marker_list_.push_back(CreateMarker(20, 30));
 
-  EXPECT_TRUE(marker_list_->RemoveMarkers(19, 12));
+  EXPECT_TRUE(
+      UnsortedDocumentMarkerListEditor::RemoveMarkers(&marker_list_, 19, 12));
 
-  DocumentMarkerVector markers = marker_list_->GetMarkers();
-  std::sort(markers.begin(), markers.end(), compare_markers);
+  std::sort(marker_list_.begin(), marker_list_.end(), compare_markers);
 
-  EXPECT_EQ(2u, markers.size());
+  EXPECT_EQ(2u, marker_list_.size());
 
-  EXPECT_EQ(0u, markers[0]->StartOffset());
-  EXPECT_EQ(10u, markers[0]->EndOffset());
+  EXPECT_EQ(0u, marker_list_[0]->StartOffset());
+  EXPECT_EQ(10u, marker_list_[0]->EndOffset());
 
-  EXPECT_EQ(40u, markers[1]->StartOffset());
-  EXPECT_EQ(50u, markers[1]->EndOffset());
+  EXPECT_EQ(40u, marker_list_[1]->StartOffset());
+  EXPECT_EQ(50u, marker_list_[1]->EndOffset());
 }
 
 TEST_F(SuggestionMarkerListImplTest,
diff --git a/third_party/WebKit/Source/core/editing/markers/UnsortedDocumentMarkerListEditor.h b/third_party/WebKit/Source/core/editing/markers/UnsortedDocumentMarkerListEditor.h
new file mode 100644
index 0000000..ce9f008
--- /dev/null
+++ b/third_party/WebKit/Source/core/editing/markers/UnsortedDocumentMarkerListEditor.h
@@ -0,0 +1,58 @@
+// 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 UnsortedDocumentMarkerListEditor_h
+#define UnsortedDocumentMarkerListEditor_h
+
+#include "core/editing/markers/DocumentMarkerList.h"
+#include "platform/heap/Handle.h"
+
+namespace blink {
+
+class DocumentMarker;
+
+// This class holds static utility methods to be used in DocumentMarkerList
+// implementations that store potentially overlapping markers in unsorted order.
+class CORE_EXPORT UnsortedDocumentMarkerListEditor final {
+ public:
+  using MarkerList = HeapVector<Member<DocumentMarker>>;
+
+  // Returns true if a marker was moved, false otherwise.
+  static bool MoveMarkers(MarkerList* src_list,
+                          int length,
+                          DocumentMarkerList* dst_list);
+
+  // Returns true if a marker was removed, false otherwise.
+  static bool RemoveMarkers(MarkerList*, unsigned start_offset, int length);
+
+  // Returns true if a marker was shifted or removed, false otherwise.
+  // If the text marked by a marker is changed by the edit, this method attempts
+  // to keep the marker tracking the marked region rather than removing the
+  // marker.
+  static bool ShiftMarkersContentIndependent(MarkerList*,
+                                             unsigned offset,
+                                             unsigned old_length,
+                                             unsigned new_length);
+
+  // Returns the first marker in the specified MarkerList whose interior
+  // overlaps overlap with the range [start_offset, end_offset], or null if
+  // there is no such marker.
+  // Note: since the markers aren't stored in order in an unsorted marker list,
+  // the first marker found isn't necessarily going to be the first marker
+  // ordered by start or end offset.
+  static DocumentMarker* FirstMarkerIntersectingRange(const MarkerList&,
+                                                      unsigned start_offset,
+                                                      unsigned end_offset);
+
+  // Returns all markers in the specified MarkerList whose interior overlaps
+  // with the range [start_offset, end_offset].
+  static HeapVector<Member<DocumentMarker>> MarkersIntersectingRange(
+      const MarkerList&,
+      unsigned start_offset,
+      unsigned end_offset);
+};
+
+}  // namespace blink
+
+#endif  // UnsortedDocumentMarkerListEditor_h
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/HotModeSpellCheckRequester.cpp b/third_party/WebKit/Source/core/editing/spellcheck/HotModeSpellCheckRequester.cpp
index 4c98b39..319297e 100644
--- a/third_party/WebKit/Source/core/editing/spellcheck/HotModeSpellCheckRequester.cpp
+++ b/third_party/WebKit/Source/core/editing/spellcheck/HotModeSpellCheckRequester.cpp
@@ -87,8 +87,8 @@
   TextIteratorBehavior behavior = TextIteratorBehavior::Builder()
                                       .SetEmitsObjectReplacementCharacter(true)
                                       .Build();
-  BackwardsCharacterIterator backward_iterator(full_range.StartPosition(),
-                                               position, behavior);
+  BackwardsCharacterIterator backward_iterator(
+      EphemeralRange(full_range.StartPosition(), position), behavior);
   if (!backward_iterator.AtEnd())
     backward_iterator.Advance(kHotModeChunkSize / 2);
   const Position& chunk_start = backward_iterator.EndPosition();
diff --git a/third_party/WebKit/Source/core/html/BUILD.gn b/third_party/WebKit/Source/core/html/BUILD.gn
index 1ead934..2504066 100644
--- a/third_party/WebKit/Source/core/html/BUILD.gn
+++ b/third_party/WebKit/Source/core/html/BUILD.gn
@@ -94,8 +94,6 @@
     "HTMLHtmlElement.h",
     "HTMLIFrameElement.cpp",
     "HTMLIFrameElement.h",
-    "HTMLIFrameElementAllow.cpp",
-    "HTMLIFrameElementAllow.h",
     "HTMLIFrameElementSandbox.cpp",
     "HTMLIFrameElementSandbox.h",
     "HTMLImageElement.cpp",
diff --git a/third_party/WebKit/Source/core/html/HTMLFrameElement.cpp b/third_party/WebKit/Source/core/html/HTMLFrameElement.cpp
index af8e424..3a936e2 100644
--- a/third_party/WebKit/Source/core/html/HTMLFrameElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLFrameElement.cpp
@@ -77,7 +77,7 @@
 }
 
 Vector<WebParsedFeaturePolicyDeclaration>
-HTMLFrameElement::ConstructContainerPolicy() const {
+HTMLFrameElement::ConstructContainerPolicy(Vector<String>*) const {
   // Frame elements are not allowed to enable the fullscreen feature. Add an
   // empty whitelist for the fullscreen feature so that the framed content is
   // unable to use the API, regardless of origin.
diff --git a/third_party/WebKit/Source/core/html/HTMLFrameElement.h b/third_party/WebKit/Source/core/html/HTMLFrameElement.h
index e80e8e5..e75b0fa 100644
--- a/third_party/WebKit/Source/core/html/HTMLFrameElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLFrameElement.h
@@ -39,8 +39,8 @@
 
   bool NoResize() const;
 
-  Vector<WebParsedFeaturePolicyDeclaration> ConstructContainerPolicy()
-      const override;
+  Vector<WebParsedFeaturePolicyDeclaration> ConstructContainerPolicy(
+      Vector<String>*) const override;
 
  private:
   explicit HTMLFrameElement(Document&);
diff --git a/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.cpp b/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.cpp
index 0aa06eb4..a2960334 100644
--- a/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.cpp
@@ -144,7 +144,7 @@
   sandbox_flags_ = flags;
   // Recalculate the container policy in case the allow-same-origin flag has
   // changed.
-  container_policy_ = ConstructContainerPolicy();
+  container_policy_ = ConstructContainerPolicy(nullptr);
 
   // Don't notify about updates if ContentFrame() is null, for example when
   // the subframe hasn't been created yet.
@@ -165,8 +165,8 @@
     plugin->Dispose();
 }
 
-void HTMLFrameOwnerElement::UpdateContainerPolicy() {
-  container_policy_ = ConstructContainerPolicy();
+void HTMLFrameOwnerElement::UpdateContainerPolicy(Vector<String>* messages) {
+  container_policy_ = ConstructContainerPolicy(messages);
   // Don't notify about updates if ContentFrame() is null, for example when
   // the subframe hasn't been created yet.
   if (ContentFrame()) {
diff --git a/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.h b/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.h
index 5046ce54..09d4788 100644
--- a/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.h
@@ -131,12 +131,12 @@
   // Return a feature policy container policy for this frame, based on the
   // frame attributes and the effective origin specified in the frame
   // attributes.
-  virtual Vector<WebParsedFeaturePolicyDeclaration> ConstructContainerPolicy()
-      const = 0;
+  virtual Vector<WebParsedFeaturePolicyDeclaration> ConstructContainerPolicy(
+      Vector<String>*) const = 0;
 
   // Update the container policy and notify the frame loader client of any
   // changes.
-  void UpdateContainerPolicy();
+  void UpdateContainerPolicy(Vector<String>* messages = nullptr);
 
  private:
   // Intentionally private to prevent redundant checks when the type is
diff --git a/third_party/WebKit/Source/core/html/HTMLIFrameElement.cpp b/third_party/WebKit/Source/core/html/HTMLIFrameElement.cpp
index 730b7d1..b9ea7f0 100644
--- a/third_party/WebKit/Source/core/html/HTMLIFrameElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLIFrameElement.cpp
@@ -42,14 +42,12 @@
       did_load_non_empty_document_(false),
       collapsed_by_client_(false),
       sandbox_(HTMLIFrameElementSandbox::Create(this)),
-      allow_(HTMLIFrameElementAllow::Create(this)),
       referrer_policy_(kReferrerPolicyDefault) {}
 
 DEFINE_NODE_FACTORY(HTMLIFrameElement)
 
 DEFINE_TRACE(HTMLIFrameElement) {
   visitor->Trace(sandbox_);
-  visitor->Trace(allow_);
   HTMLFrameElementBase::Trace(visitor);
   Supplementable<HTMLIFrameElement>::Trace(visitor);
 }
@@ -72,10 +70,6 @@
   return sandbox_.Get();
 }
 
-DOMTokenList* HTMLIFrameElement::allow() const {
-  return allow_.Get();
-}
-
 bool HTMLIFrameElement::IsPresentationAttribute(
     const QualifiedName& name) const {
   if (name == widthAttr || name == heightAttr || name == alignAttr ||
@@ -175,22 +169,25 @@
           "'csp' attribute is not a valid policy: " + value));
       return;
     }
-    AtomicString old_csp = csp_;
-    csp_ = value;
-    if (csp_ != old_csp)
+    if (csp_ != value) {
+      csp_ = value;
       FrameOwnerPropertiesChanged();
+    }
   } else if (RuntimeEnabledFeatures::FeaturePolicyEnabled() &&
              name == allowAttr) {
-    allow_->DidUpdateAttributeValue(params.old_value, value);
-    String invalid_tokens;
-    allowed_features_ = allow_->ParseAllowedFeatureNames(invalid_tokens);
-    if (!invalid_tokens.IsNull()) {
-      GetDocument().AddConsoleMessage(ConsoleMessage::Create(
-          kOtherMessageSource, kErrorMessageLevel,
-          "Error while parsing the 'allow' attribute: " + invalid_tokens));
+    if (allow_ != value) {
+      allow_ = value;
+      Vector<String> messages;
+      UpdateContainerPolicy(&messages);
+      UseCounter::Count(GetDocument(),
+                        WebFeature::kFeaturePolicyAllowAttribute);
+      if (!messages.IsEmpty()) {
+        for (const String& message : messages) {
+          GetDocument().AddConsoleMessage(ConsoleMessage::Create(
+              kOtherMessageSource, kWarningMessageLevel, message));
+        }
+      }
     }
-    UpdateContainerPolicy();
-    UseCounter::Count(GetDocument(), WebFeature::kFeaturePolicyAllowAttribute);
   } else {
     if (name == srcAttr)
       LogUpdateAttributeIfIsolatedWorldAndInDocument("iframe", params);
@@ -199,17 +196,11 @@
 }
 
 Vector<WebParsedFeaturePolicyDeclaration>
-HTMLIFrameElement::ConstructContainerPolicy() const {
-  RefPtr<SecurityOrigin> origin = GetOriginForFeaturePolicy();
-  Vector<WebParsedFeaturePolicyDeclaration> container_policy;
-
-  // Populate the initial container policy from the allow attribute.
-  for (const WebFeaturePolicyFeature feature : allowed_features_) {
-    WebParsedFeaturePolicyDeclaration whitelist;
-    whitelist.feature = feature;
-    whitelist.origins = Vector<WebSecurityOrigin>(1UL, {origin});
-    container_policy.push_back(whitelist);
-  }
+HTMLIFrameElement::ConstructContainerPolicy(Vector<String>* messages) const {
+  RefPtr<SecurityOrigin> src_origin = GetOriginForFeaturePolicy();
+  RefPtr<SecurityOrigin> self_origin = GetDocument().GetSecurityOrigin();
+  Vector<WebParsedFeaturePolicyDeclaration> container_policy =
+      ParseFeaturePolicyAttribute(allow_, self_origin, src_origin, messages);
 
   // If allowfullscreen attribute is present and no fullscreen policy is set,
   // enable the feature for all origins.
@@ -218,6 +209,10 @@
     for (const auto& declaration : container_policy) {
       if (declaration.feature == WebFeaturePolicyFeature::kFullscreen) {
         has_fullscreen_policy = true;
+        if (messages) {
+          messages->push_back(
+              "allow attribute is overriding 'allowfullscreen'.");
+        }
         break;
       }
     }
@@ -236,6 +231,10 @@
     for (const auto& declaration : container_policy) {
       if (declaration.feature == WebFeaturePolicyFeature::kPayment) {
         has_payment_policy = true;
+        if (messages) {
+          messages->push_back(
+              "allow attribute is overriding 'allowpaymentrequest'.");
+        }
         break;
       }
     }
diff --git a/third_party/WebKit/Source/core/html/HTMLIFrameElement.h b/third_party/WebKit/Source/core/html/HTMLIFrameElement.h
index c4111f8..0d81880 100644
--- a/third_party/WebKit/Source/core/html/HTMLIFrameElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLIFrameElement.h
@@ -26,7 +26,6 @@
 
 #include "core/CoreExport.h"
 #include "core/html/HTMLFrameElementBase.h"
-#include "core/html/HTMLIFrameElementAllow.h"
 #include "core/html/HTMLIFrameElementSandbox.h"
 #include "platform/Supplementable.h"
 #include "public/platform/WebFeaturePolicy.h"
@@ -45,10 +44,9 @@
   DECLARE_VIRTUAL_TRACE();
   ~HTMLIFrameElement() override;
   DOMTokenList* sandbox() const;
-  DOMTokenList* allow() const;
 
-  Vector<WebParsedFeaturePolicyDeclaration> ConstructContainerPolicy()
-      const override;
+  Vector<WebParsedFeaturePolicyDeclaration> ConstructContainerPolicy(
+      Vector<String>* messages = nullptr) const override;
 
  private:
   explicit HTMLIFrameElement(Document&);
@@ -84,14 +82,12 @@
 
   AtomicString name_;
   AtomicString csp_;
+  AtomicString allow_;
   bool did_load_non_empty_document_;
   bool allow_fullscreen_;
   bool allow_payment_request_;
   bool collapsed_by_client_;
   Member<HTMLIFrameElementSandbox> sandbox_;
-  Member<HTMLIFrameElementAllow> allow_;
-
-  WebVector<WebFeaturePolicyFeature> allowed_features_;
 
   ReferrerPolicy referrer_policy_;
 };
diff --git a/third_party/WebKit/Source/core/html/HTMLIFrameElement.idl b/third_party/WebKit/Source/core/html/HTMLIFrameElement.idl
index c6c13d1d..fd0ef48 100644
--- a/third_party/WebKit/Source/core/html/HTMLIFrameElement.idl
+++ b/third_party/WebKit/Source/core/html/HTMLIFrameElement.idl
@@ -39,7 +39,7 @@
 
     // Feature Policy allow attribute
     // https://wicg.github.io/feature-policy/
-    [RuntimeEnabled=FeaturePolicy, CEReactions, PutForwards=value] readonly attribute DOMTokenList allow;
+    [RuntimeEnabled=FeaturePolicy, CEReactions, Reflect] attribute DOMString allow;
     // obsolete members
     // https://html.spec.whatwg.org/#HTMLIFrameElement-partial
     [CEReactions, Reflect] attribute DOMString align;
diff --git a/third_party/WebKit/Source/core/html/HTMLIFrameElementAllow.cpp b/third_party/WebKit/Source/core/html/HTMLIFrameElementAllow.cpp
deleted file mode 100644
index 37ec3f8..0000000
--- a/third_party/WebKit/Source/core/html/HTMLIFrameElementAllow.cpp
+++ /dev/null
@@ -1,59 +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 "core/html/HTMLIFrameElementAllow.h"
-
-#include "core/html/HTMLIFrameElement.h"
-#include "platform/feature_policy/FeaturePolicy.h"
-#include "platform/wtf/text/StringBuilder.h"
-
-using blink::WebFeaturePolicyFeature;
-
-namespace blink {
-
-HTMLIFrameElementAllow::HTMLIFrameElementAllow(HTMLIFrameElement* element)
-    : DOMTokenList(*element, HTMLNames::allowAttr) {}
-
-Vector<WebFeaturePolicyFeature>
-HTMLIFrameElementAllow::ParseAllowedFeatureNames(
-    String& invalid_tokens_error_message) const {
-  Vector<WebFeaturePolicyFeature> feature_names;
-  unsigned num_token_errors = 0;
-  StringBuilder token_errors;
-  const SpaceSplitString& token_set = this->TokenSet();
-
-  // Collects a list of valid feature names.
-  const FeatureNameMap& feature_name_map = GetDefaultFeatureNameMap();
-  for (size_t i = 0; i < token_set.size(); ++i) {
-    const AtomicString& token = token_set[i];
-    if (!feature_name_map.Contains(token)) {
-      token_errors.Append(token_errors.IsEmpty() ? "'" : ", '");
-      token_errors.Append(token);
-      token_errors.Append("'");
-      ++num_token_errors;
-    } else {
-      feature_names.push_back(feature_name_map.at(token));
-    }
-  }
-
-  if (num_token_errors) {
-    token_errors.Append(num_token_errors > 1 ? " are invalid feature names."
-                                             : " is an invalid feature name.");
-    invalid_tokens_error_message = token_errors.ToString();
-  }
-
-  // Create a unique set of feature names.
-  std::sort(feature_names.begin(), feature_names.end());
-  auto it = std::unique(feature_names.begin(), feature_names.end());
-  feature_names.Shrink(it - feature_names.begin());
-
-  return feature_names;
-}
-
-bool HTMLIFrameElementAllow::ValidateTokenValue(const AtomicString& token_value,
-                                                ExceptionState&) const {
-  return GetDefaultFeatureNameMap().Contains(token_value.GetString());
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/core/html/HTMLIFrameElementAllow.h b/third_party/WebKit/Source/core/html/HTMLIFrameElementAllow.h
deleted file mode 100644
index 46c2e62a..0000000
--- a/third_party/WebKit/Source/core/html/HTMLIFrameElementAllow.h
+++ /dev/null
@@ -1,34 +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 HTMLIFrameElementAllow_h
-#define HTMLIFrameElementAllow_h
-
-#include "core/CoreExport.h"
-#include "core/dom/DOMTokenList.h"
-#include "platform/heap/Handle.h"
-#include "public/platform/WebFeaturePolicy.h"
-
-namespace blink {
-
-class HTMLIFrameElement;
-
-class CORE_EXPORT HTMLIFrameElementAllow final : public DOMTokenList {
- public:
-  static HTMLIFrameElementAllow* Create(HTMLIFrameElement* element) {
-    return new HTMLIFrameElementAllow(element);
-  }
-
-  // Returns unique set of valid feature names.
-  Vector<WebFeaturePolicyFeature> ParseAllowedFeatureNames(
-      String& invalid_tokens_error_message) const;
-
- private:
-  explicit HTMLIFrameElementAllow(HTMLIFrameElement*);
-  bool ValidateTokenValue(const AtomicString&, ExceptionState&) const override;
-};
-
-}  // namespace blink
-
-#endif  // HTMLIFrameElementAllow_h
diff --git a/third_party/WebKit/Source/core/html/HTMLIFrameElementAllowTest.cpp b/third_party/WebKit/Source/core/html/HTMLIFrameElementAllowTest.cpp
deleted file mode 100644
index 4861706..0000000
--- a/third_party/WebKit/Source/core/html/HTMLIFrameElementAllowTest.cpp
+++ /dev/null
@@ -1,65 +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 "core/html/HTMLIFrameElementAllow.h"
-
-#include "core/dom/Document.h"
-#include "core/html/HTMLIFrameElement.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using ::testing::UnorderedElementsAre;
-
-namespace blink {
-
-TEST(HTMLIFrameElementAllowTest, ParseAllowedFeatureNamesValid) {
-  Document* document = Document::CreateForTest();
-  HTMLIFrameElement* iframe = HTMLIFrameElement::Create(*document);
-  HTMLIFrameElementAllow* allow =
-      static_cast<HTMLIFrameElementAllow*>(iframe->allow());
-  String error_message;
-  Vector<WebFeaturePolicyFeature> result;
-
-  allow->setValue("");
-  result = allow->ParseAllowedFeatureNames(error_message);
-  EXPECT_TRUE(result.IsEmpty());
-
-  allow->setValue("fullscreen");
-  result = allow->ParseAllowedFeatureNames(error_message);
-  EXPECT_THAT(result,
-              UnorderedElementsAre(WebFeaturePolicyFeature::kFullscreen));
-
-  allow->setValue("fullscreen payment");
-  result = allow->ParseAllowedFeatureNames(error_message);
-  EXPECT_THAT(result, UnorderedElementsAre(WebFeaturePolicyFeature::kFullscreen,
-                                           WebFeaturePolicyFeature::kPayment));
-}
-
-TEST(HTMLIFrameElementAllowTest, ParseAllowedFeatureNamesInvalid) {
-  Document* document = Document::CreateForTest();
-  HTMLIFrameElement* iframe = HTMLIFrameElement::Create(*document);
-  HTMLIFrameElementAllow* allow =
-      static_cast<HTMLIFrameElementAllow*>(iframe->allow());
-  String error_message;
-  Vector<WebFeaturePolicyFeature> result;
-
-  allow->setValue("invalid");
-  result = allow->ParseAllowedFeatureNames(error_message);
-  EXPECT_TRUE(result.IsEmpty());
-  EXPECT_EQ("'invalid' is an invalid feature name.", error_message);
-
-  allow->setValue("fullscreen invalid1 invalid2");
-  result = allow->ParseAllowedFeatureNames(error_message);
-  EXPECT_THAT(result,
-              UnorderedElementsAre(WebFeaturePolicyFeature::kFullscreen));
-  EXPECT_EQ("'invalid1', 'invalid2' are invalid feature names.", error_message);
-
-  allow->setValue("fullscreen invalid payment fullscreen");
-  result = allow->ParseAllowedFeatureNames(error_message);
-  EXPECT_EQ("'invalid' is an invalid feature name.", error_message);
-  EXPECT_THAT(result, UnorderedElementsAre(WebFeaturePolicyFeature::kFullscreen,
-                                           WebFeaturePolicyFeature::kPayment));
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/core/html/HTMLIFrameElementTest.cpp b/third_party/WebKit/Source/core/html/HTMLIFrameElementTest.cpp
index 026865f..c353fe2 100644
--- a/third_party/WebKit/Source/core/html/HTMLIFrameElementTest.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLIFrameElementTest.cpp
@@ -16,26 +16,6 @@
   }
 };
 
-// Test setting feature policy via the Element attribute (HTML codepath).
-TEST_F(HTMLIFrameElementTest, SetAllowAttribute) {
-  Document* document = Document::CreateForTest();
-  HTMLIFrameElement* iframe = HTMLIFrameElement::Create(*document);
-
-  iframe->setAttribute(HTMLNames::allowAttr, "fullscreen");
-  EXPECT_EQ("fullscreen", iframe->allow()->value());
-  iframe->setAttribute(HTMLNames::allowAttr, "fullscreen vibrate");
-  EXPECT_EQ("fullscreen vibrate", iframe->allow()->value());
-}
-
-// Test setting feature policy via the DOMTokenList (JS codepath).
-TEST_F(HTMLIFrameElementTest, SetAllowAttributeJS) {
-  Document* document = Document::CreateForTest();
-  HTMLIFrameElement* iframe = HTMLIFrameElement::Create(*document);
-
-  iframe->allow()->setValue("fullscreen");
-  EXPECT_EQ("fullscreen", iframe->getAttribute(HTMLNames::allowAttr));
-}
-
 // Test that the correct origin is used when constructing the container policy,
 // and that frames which should inherit their parent document's origin do so.
 TEST_F(HTMLIFrameElementTest, FramesUseCorrectOrigin) {
@@ -213,7 +193,7 @@
   EXPECT_EQ(1UL, container_policy1[0].origins.size());
   EXPECT_EQ("http://example.net", container_policy1[0].origins[0].ToString());
 
-  frame_element->setAttribute(HTMLNames::allowAttr, "payment fullscreen");
+  frame_element->setAttribute(HTMLNames::allowAttr, "payment; fullscreen");
   frame_element->UpdateContainerPolicyForTests();
 
   const WebParsedFeaturePolicy& container_policy2 =
@@ -231,6 +211,26 @@
   EXPECT_FALSE(container_policy2[1].matches_all_origins);
   EXPECT_EQ(1UL, container_policy2[1].origins.size());
   EXPECT_EQ("http://example.net", container_policy2[1].origins[0].ToString());
+
+  // TODO(lunalu): Remove this test when deprecating the old syntax.
+  // Test for supporting old allow syntax.
+  frame_element->setAttribute(HTMLNames::allowAttr, "payment fullscreen");
+
+  const WebParsedFeaturePolicy& container_policy3 =
+      frame_element->ContainerPolicy();
+  EXPECT_EQ(2UL, container_policy3.size());
+  EXPECT_TRUE(
+      container_policy3[0].feature == WebFeaturePolicyFeature::kFullscreen ||
+      container_policy3[1].feature == WebFeaturePolicyFeature::kFullscreen);
+  EXPECT_TRUE(
+      container_policy3[0].feature == WebFeaturePolicyFeature::kPayment ||
+      container_policy3[1].feature == WebFeaturePolicyFeature::kPayment);
+  EXPECT_FALSE(container_policy3[0].matches_all_origins);
+  EXPECT_EQ(1UL, container_policy3[0].origins.size());
+  EXPECT_EQ("http://example.net", container_policy3[0].origins[0].ToString());
+  EXPECT_FALSE(container_policy3[1].matches_all_origins);
+  EXPECT_EQ(1UL, container_policy3[1].origins.size());
+  EXPECT_EQ("http://example.net", container_policy3[1].origins[0].ToString());
 }
 
 // Test that the allow attribute on a sandboxed frame results in a container
@@ -296,7 +296,7 @@
   HTMLIFrameElement* frame_element = HTMLIFrameElement::Create(*document);
 
   WebParsedFeaturePolicy container_policy =
-      frame_element->ConstructContainerPolicy();
+      frame_element->ConstructContainerPolicy(nullptr);
   EXPECT_EQ(0UL, container_policy.size());
 }
 
@@ -309,9 +309,9 @@
   document->UpdateSecurityOrigin(SecurityOrigin::Create(document_url));
 
   HTMLIFrameElement* frame_element = HTMLIFrameElement::Create(*document);
-  frame_element->setAttribute(HTMLNames::allowAttr, "payment usb");
+  frame_element->setAttribute(HTMLNames::allowAttr, "payment; usb");
   WebParsedFeaturePolicy container_policy =
-      frame_element->ConstructContainerPolicy();
+      frame_element->ConstructContainerPolicy(nullptr);
   EXPECT_EQ(2UL, container_policy.size());
   EXPECT_EQ(WebFeaturePolicyFeature::kPayment, container_policy[0].feature);
   EXPECT_FALSE(container_policy[0].matches_all_origins);
@@ -339,7 +339,7 @@
   frame_element->SetBooleanAttribute(HTMLNames::allowfullscreenAttr, true);
 
   WebParsedFeaturePolicy container_policy =
-      frame_element->ConstructContainerPolicy();
+      frame_element->ConstructContainerPolicy(nullptr);
   EXPECT_EQ(1UL, container_policy.size());
   EXPECT_EQ(WebFeaturePolicyFeature::kFullscreen, container_policy[0].feature);
   EXPECT_TRUE(container_policy[0].matches_all_origins);
@@ -358,7 +358,7 @@
   frame_element->SetBooleanAttribute(HTMLNames::allowpaymentrequestAttr, true);
 
   WebParsedFeaturePolicy container_policy =
-      frame_element->ConstructContainerPolicy();
+      frame_element->ConstructContainerPolicy(nullptr);
   EXPECT_EQ(2UL, container_policy.size());
   EXPECT_EQ(WebFeaturePolicyFeature::kUsb, container_policy[0].feature);
   EXPECT_FALSE(container_policy[0].matches_all_origins);
@@ -383,12 +383,12 @@
   document->UpdateSecurityOrigin(SecurityOrigin::Create(document_url));
 
   HTMLIFrameElement* frame_element = HTMLIFrameElement::Create(*document);
-  frame_element->setAttribute(HTMLNames::allowAttr, "payment usb");
+  frame_element->setAttribute(HTMLNames::allowAttr, "payment; usb");
   frame_element->SetBooleanAttribute(HTMLNames::allowfullscreenAttr, true);
   frame_element->SetBooleanAttribute(HTMLNames::allowpaymentrequestAttr, true);
 
   WebParsedFeaturePolicy container_policy =
-      frame_element->ConstructContainerPolicy();
+      frame_element->ConstructContainerPolicy(nullptr);
   EXPECT_EQ(3UL, container_policy.size());
   EXPECT_EQ(WebFeaturePolicyFeature::kPayment, container_policy[0].feature);
   EXPECT_FALSE(container_policy[0].matches_all_origins);
diff --git a/third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp b/third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp
index 0542b819f..989865f 100644
--- a/third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp
@@ -269,7 +269,7 @@
 }
 
 Vector<WebParsedFeaturePolicyDeclaration>
-HTMLPlugInElement::ConstructContainerPolicy() const {
+HTMLPlugInElement::ConstructContainerPolicy(Vector<String>*) const {
   // Plugin elements (<object> and <embed>) are not allowed to enable the
   // fullscreen feature. Add an empty whitelist for the fullscreen feature so
   // that the nested browsing context is unable to use the API, regardless of
diff --git a/third_party/WebKit/Source/core/html/HTMLPlugInElement.h b/third_party/WebKit/Source/core/html/HTMLPlugInElement.h
index 5458b29..4f4e18ba 100644
--- a/third_party/WebKit/Source/core/html/HTMLPlugInElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLPlugInElement.h
@@ -83,8 +83,8 @@
   void RequestPluginCreationWithoutLayoutObjectIfPossible();
   void CreatePluginWithoutLayoutObject();
 
-  virtual Vector<WebParsedFeaturePolicyDeclaration> ConstructContainerPolicy()
-      const;
+  virtual Vector<WebParsedFeaturePolicyDeclaration> ConstructContainerPolicy(
+      Vector<String>*) const;
 
  protected:
   HTMLPlugInElement(const QualifiedName& tag_name,
diff --git a/third_party/WebKit/Source/core/inspector/browser_protocol.json b/third_party/WebKit/Source/core/inspector/browser_protocol.json
index a6717dc1..acb70c5 100644
--- a/third_party/WebKit/Source/core/inspector/browser_protocol.json
+++ b/third_party/WebKit/Source/core/inspector/browser_protocol.json
@@ -2128,9 +2128,9 @@
                 "type": "object",
                 "description": "Data entry.",
                 "properties": [
-                    { "name": "request", "type": "string", "description": "Request url spec." },
-                    { "name": "response", "type": "string", "description": "Response status text." },
-                    { "name": "responseTime", "type": "number", "description": "Number of seconds since epoch." }
+                    { "name": "requestURL", "type": "string", "description": "Request URL." },
+                    { "name": "responseTime", "type": "number", "description": "Number of seconds since epoch." },
+                    { "name": "responseHeaders", "type": "array", "items": { "$ref": "Header" }, "description": "Response headers" }
                 ]
             },
             {
@@ -2144,11 +2144,18 @@
                 ]
             },
             {
+                "id": "Header",
+                "type": "object",
+                "properties": [
+                    { "name": "name", "type": "string" },
+                    { "name": "value", "type": "string" }
+                ]
+            },
+            {
                 "id": "CachedResponse",
                 "type": "object",
                 "description": "Cached response",
                 "properties": [
-                    { "name": "headers", "type": "object", "description": "Response headers" },
                     { "name": "body", "type": "string", "description": "Entry content, base64-encoded." }
                 ]
             }
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableSection.cpp b/third_party/WebKit/Source/core/layout/LayoutTableSection.cpp
index ccf7e77..be213a9 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTableSection.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTableSection.cpp
@@ -1299,7 +1299,7 @@
         // width needs to be adjusted accordingly
         int collapsed_width = 0;
         cell->SetIsSpanningCollapsedColumn(false);
-        unsigned end_col = cell->ColSpan() + c;
+        unsigned end_col = std::min(cell->ColSpan() + c, n_cols);
         for (unsigned spanning = c; spanning < end_col; spanning++)
           collapsed_width += col_collapsed_width[spanning];
         cell->SetLogicalWidth(cell->LogicalWidth() - collapsed_width);
diff --git a/third_party/WebKit/Source/core/layout/line/BreakingContextInlineHeaders.h b/third_party/WebKit/Source/core/layout/line/BreakingContextInlineHeaders.h
index 8d729801..9ca0d85 100644
--- a/third_party/WebKit/Source/core/layout/line/BreakingContextInlineHeaders.h
+++ b/third_party/WebKit/Source/core/layout/line/BreakingContextInlineHeaders.h
@@ -743,11 +743,8 @@
   // However, doing so can hit the performance when a "word" is really long,
   // such as minimized JS, because the next line will re-shape the rest of the
   // word in the current architecture.
-  // This function is a heuristic optimization to stop at 4em overflow.
-  // The longest common ligature is Emoji ZWJ sequence, which ligates 4 Emoji
-  // into 1 at maximum as of v5.0. This sequence requires 3em overflow, and 1em
-  // for a rainy day fund.
-  float overflow_allowance = 4 * font.GetFontDescription().ComputedSize();
+  // This function is a heuristic optimization to stop at 2em overflow.
+  float overflow_allowance = 2 * font.GetFontDescription().ComputedSize();
 
   width_from_last_breaking_opportunity += char_width;
   unsigned char_len;
diff --git a/third_party/WebKit/Source/core/layout/line/InlineFlowBox.cpp b/third_party/WebKit/Source/core/layout/line/InlineFlowBox.cpp
index f49b7a2..08e67a2 100644
--- a/third_party/WebKit/Source/core/layout/line/InlineFlowBox.cpp
+++ b/third_party/WebKit/Source/core/layout/line/InlineFlowBox.cpp
@@ -91,6 +91,58 @@
          child_style.VerticalAlign() == EVerticalAlign::kBaseline;
 }
 
+inline bool InlineFlowBox::HasEmphasisMarkBefore(
+    const InlineTextBox* text_box) const {
+  TextEmphasisPosition emphasis_mark_position;
+  const auto& style =
+      text_box->GetLineLayoutItem().StyleRef(IsFirstLineStyle());
+  if (!text_box->GetEmphasisMarkPosition(style, emphasis_mark_position))
+    return false;
+  if (IsHorizontal()) {
+    return emphasis_mark_position == TextEmphasisPosition::kOverRight ||
+           emphasis_mark_position == TextEmphasisPosition::kOverLeft;
+  }
+  if (style.IsFlippedLinesWritingMode()) {
+    return emphasis_mark_position == TextEmphasisPosition::kOverLeft ||
+           emphasis_mark_position == TextEmphasisPosition::kUnderLeft;
+  }
+  if (style.IsFlippedBlocksWritingMode()) {
+    return emphasis_mark_position == TextEmphasisPosition::kOverRight ||
+           emphasis_mark_position == TextEmphasisPosition::kUnderRight;
+  }
+  return false;
+}
+
+inline bool InlineFlowBox::HasEmphasisMarkOver(
+    const InlineTextBox* text_box) const {
+  TextEmphasisPosition emphasis_mark_position;
+  if (!text_box->GetEmphasisMarkPosition(
+          text_box->GetLineLayoutItem().StyleRef(IsFirstLineStyle()),
+          emphasis_mark_position))
+    return false;
+
+  return IsHorizontal()
+             ? emphasis_mark_position == TextEmphasisPosition::kOverRight ||
+                   emphasis_mark_position == TextEmphasisPosition::kOverLeft
+             : emphasis_mark_position == TextEmphasisPosition::kOverRight ||
+                   emphasis_mark_position == TextEmphasisPosition::kUnderRight;
+}
+
+inline bool InlineFlowBox::HasEmphasisMarkUnder(
+    const InlineTextBox* text_box) const {
+  TextEmphasisPosition emphasis_mark_position;
+  if (!text_box->GetEmphasisMarkPosition(
+          text_box->GetLineLayoutItem().StyleRef(IsFirstLineStyle()),
+          emphasis_mark_position))
+    return false;
+
+  return IsHorizontal()
+             ? emphasis_mark_position == TextEmphasisPosition::kUnderRight ||
+                   emphasis_mark_position == TextEmphasisPosition::kUnderLeft
+             : emphasis_mark_position == TextEmphasisPosition::kOverLeft ||
+                   emphasis_mark_position == TextEmphasisPosition::kUnderLeft;
+}
+
 void InlineFlowBox::AddToLine(InlineBox* child) {
   DCHECK(!child->Parent());
   DCHECK(!child->NextOnLine());
@@ -823,11 +875,7 @@
         if (ToInlineTextBox(curr)->GetEmphasisMarkPosition(
                 curr->GetLineLayoutItem().StyleRef(IsFirstLineStyle()),
                 emphasis_mark_position)) {
-          bool emphasis_mark_is_over =
-              emphasis_mark_position == TextEmphasisPosition::kOver;
-          if (emphasis_mark_is_over != curr->GetLineLayoutItem()
-                                           .Style(IsFirstLineStyle())
-                                           ->IsFlippedLinesWritingMode())
+          if (HasEmphasisMarkBefore(ToInlineTextBox(curr)))
             has_annotations_before = true;
           else
             has_annotations_after = true;
@@ -1051,8 +1099,7 @@
       text_box->GetEmphasisMarkPosition(style, emphasis_mark_position)) {
     float emphasis_mark_height =
         style.GetFont().EmphasisMarkHeight(style.TextEmphasisMarkString());
-    if ((emphasis_mark_position == TextEmphasisPosition::kOver) ==
-        (!style.IsFlippedLinesWritingMode()))
+    if (HasEmphasisMarkBefore(text_box))
       top_glyph_overflow = std::min(top_glyph_overflow, -emphasis_mark_height);
     else
       bottom_glyph_overflow =
@@ -1553,7 +1600,7 @@
       if (style.GetTextEmphasisMark() != TextEmphasisMark::kNone &&
           ToInlineTextBox(curr)->GetEmphasisMarkPosition(
               style, emphasis_mark_position) &&
-          emphasis_mark_position == TextEmphasisPosition::kOver) {
+          HasEmphasisMarkOver(ToInlineTextBox(curr))) {
         if (!style.IsFlippedLinesWritingMode()) {
           int top_of_emphasis_mark =
               (curr->LogicalTop() - style.GetFont().EmphasisMarkHeight(
@@ -1621,7 +1668,7 @@
       const ComputedStyle& style =
           curr->GetLineLayoutItem().StyleRef(IsFirstLineStyle());
       if (style.GetTextEmphasisMark() != TextEmphasisMark::kNone &&
-          style.GetTextEmphasisPosition() == TextEmphasisPosition::kUnder) {
+          HasEmphasisMarkUnder(ToInlineTextBox(curr))) {
         if (!style.IsFlippedLinesWritingMode()) {
           LayoutUnit bottom_of_emphasis_mark =
               curr->LogicalBottom() + style.GetFont().EmphasisMarkHeight(
diff --git a/third_party/WebKit/Source/core/layout/line/InlineFlowBox.h b/third_party/WebKit/Source/core/layout/line/InlineFlowBox.h
index f9dffd73..a5fb1be3 100644
--- a/third_party/WebKit/Source/core/layout/line/InlineFlowBox.h
+++ b/third_party/WebKit/Source/core/layout/line/InlineFlowBox.h
@@ -433,6 +433,9 @@
   void AddReplacedChildOverflow(const InlineBox*,
                                 LayoutRect& logical_layout_overflow,
                                 LayoutRect& logical_visual_overflow);
+  bool HasEmphasisMarkBefore(const InlineTextBox*) const;
+  bool HasEmphasisMarkOver(const InlineTextBox*) const;
+  bool HasEmphasisMarkUnder(const InlineTextBox*) const;
 
   void SetLayoutOverflow(const LayoutRect&, const LayoutRect&);
   void SetVisualOverflow(const LayoutRect&, const LayoutRect&);
diff --git a/third_party/WebKit/Source/core/layout/line/InlineTextBox.cpp b/third_party/WebKit/Source/core/layout/line/InlineTextBox.cpp
index 30be2eae..fdea5348 100644
--- a/third_party/WebKit/Source/core/layout/line/InlineTextBox.cpp
+++ b/third_party/WebKit/Source/core/layout/line/InlineTextBox.cpp
@@ -507,7 +507,12 @@
 
   emphasis_position = style.GetTextEmphasisPosition();
   // Ruby text is always over, so it cannot suppress emphasis marks under.
-  if (emphasis_position == TextEmphasisPosition::kUnder)
+  if ((IsHorizontal() &&
+       (emphasis_position == TextEmphasisPosition::kUnderRight ||
+        emphasis_position == TextEmphasisPosition::kUnderLeft)) ||
+      (!IsHorizontal() &&
+       (emphasis_position == TextEmphasisPosition::kOverLeft ||
+        emphasis_position == TextEmphasisPosition::kUnderLeft)))
     return true;
 
   LineLayoutBox containing_block = GetLineLayoutItem().ContainingBlock();
diff --git a/third_party/WebKit/Source/core/loader/DocumentLoader.cpp b/third_party/WebKit/Source/core/loader/DocumentLoader.cpp
index 86fec0e..8729a09 100644
--- a/third_party/WebKit/Source/core/loader/DocumentLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/DocumentLoader.cpp
@@ -1132,7 +1132,7 @@
   // features flag is enabled, then ignore any header received.
   // TODO(iclelland): Re-enable once the syntax is finalized. (crbug.com/737643)
   document->SetFeaturePolicy(
-      RuntimeEnabledFeatures::FeaturePolicyExperimentalFeaturesEnabled()
+      RuntimeEnabledFeatures::FeaturePolicyEnabled()
           ? response_.HttpHeaderField(HTTPNames::Feature_Policy)
           : g_empty_string);
 
diff --git a/third_party/WebKit/Source/core/paint/BoxPaintInvalidator.cpp b/third_party/WebKit/Source/core/paint/BoxPaintInvalidator.cpp
index f5e59f8..32884cc 100644
--- a/third_party/WebKit/Source/core/paint/BoxPaintInvalidator.cpp
+++ b/third_party/WebKit/Source/core/paint/BoxPaintInvalidator.cpp
@@ -202,7 +202,11 @@
   if (box_.BackgroundChangedSinceLastPaintInvalidation())
     return BackgroundInvalidationType::kFull;
 
-  if (!BackgroundGeometryDependsOnLayoutOverflowRect())
+  bool layout_overflow_change_causes_invalidation =
+      (BackgroundGeometryDependsOnLayoutOverflowRect() ||
+       BackgroundPaintsOntoScrollingContentsLayer());
+
+  if (!layout_overflow_change_causes_invalidation)
     return BackgroundInvalidationType::kNone;
 
   const LayoutRect& old_layout_overflow = box_.PreviousLayoutOverflowRect();
diff --git a/third_party/WebKit/Source/core/paint/BoxPaintInvalidatorTest.cpp b/third_party/WebKit/Source/core/paint/BoxPaintInvalidatorTest.cpp
index d500c14..de147be5 100644
--- a/third_party/WebKit/Source/core/paint/BoxPaintInvalidatorTest.cpp
+++ b/third_party/WebKit/Source/core/paint/BoxPaintInvalidatorTest.cpp
@@ -100,6 +100,11 @@
         "    border-style: solid;"
         "    border-color: red;"
         "  }"
+        "  .solid-composited-scroller {"
+        "    overflow: scroll;"
+        "    will-change: transform;"
+        "    background: #ccc;"
+        "  }"
         "  .local-background {"
         "    background-attachment: local;"
         "    overflow: scroll;"
@@ -784,4 +789,33 @@
   GetDocument().View()->SetTracksPaintInvalidations(false);
 }
 
+TEST_P(BoxPaintInvalidatorTest, CompositedSolidBackgroundResize) {
+  EnableCompositing();
+  Element* target = GetDocument().getElementById("target");
+  target->setAttribute(HTMLNames::classAttr, "solid-composited-scroller");
+  target->setInnerHTML("<div style='height: 500px'></div>",
+                       ASSERT_NO_EXCEPTION);
+  GetDocument().View()->UpdateAllLifecyclePhases();
+
+  // Resize the scroller.
+  GetDocument().View()->SetTracksPaintInvalidations(true);
+  target->setAttribute(HTMLNames::styleAttr, "width: 100px");
+  GetDocument().View()->UpdateAllLifecyclePhases();
+
+  LayoutBoxModelObject* target_object =
+      ToLayoutBoxModelObject(target->GetLayoutObject());
+  GraphicsLayer* scrolling_contents_layer =
+      target_object->Layer()->GraphicsLayerBacking();
+  const auto& invalidations =
+      scrolling_contents_layer->GetRasterInvalidationTracking()->invalidations;
+
+  ASSERT_EQ(1u, invalidations.size());
+  EXPECT_EQ(IntRect(50, 0, 50, 500), invalidations[0].rect);
+  EXPECT_EQ(static_cast<const DisplayItemClient*>(target_object),
+            invalidations[0].client);
+  EXPECT_EQ(PaintInvalidationReason::kBackgroundOnScrollingContentsLayer,
+            invalidations[0].reason);
+  GetDocument().View()->SetTracksPaintInvalidations(false);
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp b/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp
index a4b5735..84d3365 100644
--- a/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp
@@ -403,12 +403,14 @@
   int ascent = font_data ? font_data->GetFontMetrics().Ascent() : 0;
   LayoutPoint text_origin(box_origin.X(), box_origin.Y() + ascent);
 
+  const DocumentMarkerVector& markers_to_paint = ComputeMarkersToPaint();
+
   // 1. Paint backgrounds behind text if needed. Examples of such backgrounds
   // include selection and composition highlights.
   if (paint_info.phase != kPaintPhaseSelection &&
       paint_info.phase != kPaintPhaseTextClip && !is_printing) {
-    PaintDocumentMarkers(paint_info, box_origin, style_to_use, font,
-                         DocumentMarkerPaintPhase::kBackground);
+    PaintDocumentMarkers(markers_to_paint, paint_info, box_origin, style_to_use,
+                         font, DocumentMarkerPaintPhase::kBackground);
     if (have_selection) {
       if (combined_text)
         PaintSelection<InlineTextBoxPainter::PaintOptions::kCombinedText>(
@@ -526,9 +528,10 @@
     text_painter.Paint(selection_start, selection_end, length, selection_style);
   }
 
-  if (paint_info.phase == kPaintPhaseForeground)
-    PaintDocumentMarkers(paint_info, box_origin, style_to_use, font,
-                         DocumentMarkerPaintPhase::kForeground);
+  if (paint_info.phase == kPaintPhaseForeground) {
+    PaintDocumentMarkers(markers_to_paint, paint_info, box_origin, style_to_use,
+                         font, DocumentMarkerPaintPhase::kForeground);
+  }
 
   if (should_rotate) {
     context.ConcatCTM(TextPainterBase::Rotation(
@@ -636,7 +639,92 @@
                                start_pos, end_pos);
 }
 
+DocumentMarkerVector InlineTextBoxPainter::ComputeMarkersToPaint() const {
+  // We don't render composition or spelling markers that overlap suggestion
+  // markers.
+
+  Node* const node = inline_text_box_.GetLineLayoutItem().GetNode();
+  if (!node)
+    return DocumentMarkerVector();
+
+  DocumentMarkerController& document_marker_controller =
+      inline_text_box_.GetLineLayoutItem().GetDocument().Markers();
+
+  // Note: DocumentMarkerController::MarkersFor() returns markers sorted by
+  // start offset.
+  const DocumentMarkerVector& suggestion_markers =
+      document_marker_controller.MarkersFor(node, DocumentMarker::kSuggestion);
+  if (suggestion_markers.IsEmpty()) {
+    // If there are no suggestion markers, we can return early as a minor
+    // performance optimization.
+    DocumentMarker::MarkerTypes remaining_types = DocumentMarker::AllMarkers();
+    remaining_types.Remove(DocumentMarker::kSuggestion);
+    return document_marker_controller.MarkersFor(node, remaining_types);
+  }
+
+  const DocumentMarkerVector& markers_overridden_by_suggestion_markers =
+      document_marker_controller.MarkersFor(
+          node, DocumentMarker::kComposition | DocumentMarker::kSpelling);
+
+  Vector<unsigned> suggestion_starts;
+  Vector<unsigned> suggestion_ends;
+  for (const DocumentMarker* suggestion_marker : suggestion_markers) {
+    suggestion_starts.push_back(suggestion_marker->StartOffset());
+    suggestion_ends.push_back(suggestion_marker->EndOffset());
+  }
+
+  std::sort(suggestion_starts.begin(), suggestion_starts.end());
+  std::sort(suggestion_ends.begin(), suggestion_ends.end());
+
+  unsigned suggestion_starts_index = 0;
+  unsigned suggestion_ends_index = 0;
+  unsigned number_suggestions_currently_inside = 0;
+
+  DocumentMarkerVector markers_to_paint;
+  for (DocumentMarker* marker : markers_overridden_by_suggestion_markers) {
+    while (suggestion_starts_index < suggestion_starts.size() &&
+           suggestion_starts[suggestion_starts_index] <=
+               marker->StartOffset()) {
+      ++suggestion_starts_index;
+      ++number_suggestions_currently_inside;
+    }
+    while (suggestion_ends_index < suggestion_ends.size() &&
+           suggestion_ends[suggestion_ends_index] <= marker->StartOffset()) {
+      ++suggestion_ends_index;
+      --number_suggestions_currently_inside;
+    }
+
+    // At this point, number_suggestions_currently_inside should be equal to the
+    // number of suggestion markers overlapping the point marker->StartOffset()
+    // (marker endpoints don't count as overlapping).
+
+    // Marker is overlapped by a suggestion marker, do not paint.
+    if (number_suggestions_currently_inside)
+      continue;
+
+    // Verify that no suggestion marker starts before the current marker ends.
+    if (suggestion_starts_index < suggestion_starts.size() &&
+        suggestion_starts[suggestion_starts_index] < marker->EndOffset())
+      continue;
+
+    markers_to_paint.push_back(marker);
+  }
+
+  markers_to_paint.AppendVector(suggestion_markers);
+
+  DocumentMarker::MarkerTypes remaining_types = DocumentMarker::AllMarkers();
+  remaining_types.Remove(DocumentMarker::kComposition |
+                         DocumentMarker::kSpelling |
+                         DocumentMarker::kSuggestion);
+
+  markers_to_paint.AppendVector(
+      document_marker_controller.MarkersFor(node, remaining_types));
+
+  return markers_to_paint;
+}
+
 void InlineTextBoxPainter::PaintDocumentMarkers(
+    const DocumentMarkerVector& markers_to_paint,
     const PaintInfo& paint_info,
     const LayoutPoint& box_origin,
     const ComputedStyle& style,
@@ -648,15 +736,11 @@
   DCHECK(inline_text_box_.Truncation() != kCFullTruncation);
   DCHECK(inline_text_box_.Len());
 
-  DocumentMarkerVector markers =
-      inline_text_box_.GetLineLayoutItem().GetDocument().Markers().MarkersFor(
-          inline_text_box_.GetLineLayoutItem().GetNode());
-  DocumentMarkerVector::const_iterator marker_it = markers.begin();
-
+  DocumentMarkerVector::const_iterator marker_it = markers_to_paint.begin();
   // Give any document markers that touch this run a chance to draw before the
   // text has been drawn.  Note end() points at the last char, not one past it
   // like endOffset and ranges do.
-  for (; marker_it != markers.end(); ++marker_it) {
+  for (; marker_it != markers_to_paint.end(); ++marker_it) {
     DCHECK(*marker_it);
     const DocumentMarker& marker = **marker_it;
 
@@ -695,7 +779,8 @@
         }
         break;
       case DocumentMarker::kComposition:
-      case DocumentMarker::kActiveSuggestion: {
+      case DocumentMarker::kActiveSuggestion:
+      case DocumentMarker::kSuggestion: {
         const StyleableMarker& styleable_marker = ToStyleableMarker(marker);
         if (marker_paint_phase == DocumentMarkerPaintPhase::kBackground) {
           const PaintOffsets marker_offsets =
diff --git a/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.h b/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.h
index 571ce1f9..a1e9388 100644
--- a/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.h
+++ b/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.h
@@ -5,6 +5,7 @@
 #ifndef InlineTextBoxPainter_h
 #define InlineTextBoxPainter_h
 
+#include "core/editing/markers/DocumentMarker.h"
 #include "core/style/ComputedStyleConstants.h"
 #include "platform/geometry/LayoutRect.h"
 #include "platform/wtf/Allocator.h"
@@ -15,7 +16,6 @@
 
 class Color;
 class ComputedStyle;
-class DocumentMarker;
 class Font;
 class GraphicsContext;
 class InlineTextBox;
@@ -35,7 +35,15 @@
       : inline_text_box_(inline_text_box) {}
 
   void Paint(const PaintInfo&, const LayoutPoint&);
-  void PaintDocumentMarkers(const PaintInfo&,
+
+  // We don't paint composition or spelling markers that overlap a suggestion
+  // marker (to match the native Android behavior). This method lets us throw
+  // out the overlapping composition and spelling markers in O(N log N) time
+  // where N is the total number of DocumentMarkers in this node.
+  DocumentMarkerVector ComputeMarkersToPaint() const;
+
+  void PaintDocumentMarkers(const DocumentMarkerVector& markers_to_paint,
+                            const PaintInfo&,
                             const LayoutPoint& box_origin,
                             const ComputedStyle&,
                             const Font&,
diff --git a/third_party/WebKit/Source/core/paint/SVGInlineTextBoxPainter.cpp b/third_party/WebKit/Source/core/paint/SVGInlineTextBoxPainter.cpp
index 1af0b67..90a630a 100644
--- a/third_party/WebKit/Source/core/paint/SVGInlineTextBoxPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/SVGInlineTextBoxPainter.cpp
@@ -124,16 +124,18 @@
         BoundsForDrawingRecorder(paint_info, style, paint_offset,
                                  include_selection_rect));
     InlineTextBoxPainter text_painter(svg_inline_text_box_);
-    text_painter.PaintDocumentMarkers(paint_info, paint_offset, style,
-                                      text_layout_object.ScaledFont(),
-                                      DocumentMarkerPaintPhase::kBackground);
+    const DocumentMarkerVector& markers_to_paint =
+        text_painter.ComputeMarkersToPaint();
+    text_painter.PaintDocumentMarkers(
+        markers_to_paint, paint_info, paint_offset, style,
+        text_layout_object.ScaledFont(), DocumentMarkerPaintPhase::kBackground);
 
     if (!svg_inline_text_box_.TextFragments().IsEmpty())
       PaintTextFragments(paint_info, parent_layout_object);
 
-    text_painter.PaintDocumentMarkers(paint_info, paint_offset, style,
-                                      text_layout_object.ScaledFont(),
-                                      DocumentMarkerPaintPhase::kForeground);
+    text_painter.PaintDocumentMarkers(
+        markers_to_paint, paint_info, paint_offset, style,
+        text_layout_object.ScaledFont(), DocumentMarkerPaintPhase::kForeground);
   }
 }
 
diff --git a/third_party/WebKit/Source/core/paint/TextPainterBase.cpp b/third_party/WebKit/Source/core/paint/TextPainterBase.cpp
index 42f04790..6f936e7 100644
--- a/third_party/WebKit/Source/core/paint/TextPainterBase.cpp
+++ b/third_party/WebKit/Source/core/paint/TextPainterBase.cpp
@@ -41,11 +41,17 @@
 
   if (!font_data || emphasis_mark.IsNull()) {
     emphasis_mark_offset_ = 0;
-  } else if (position == TextEmphasisPosition::kOver) {
+  } else if ((horizontal_ && (position == TextEmphasisPosition::kOverRight ||
+                              position == TextEmphasisPosition::kOverLeft)) ||
+             (!horizontal_ &&
+              (position == TextEmphasisPosition::kOverRight ||
+               position == TextEmphasisPosition::kUnderRight))) {
     emphasis_mark_offset_ = -font_data->GetFontMetrics().Ascent() -
                             font_.EmphasisMarkDescent(emphasis_mark);
   } else {
-    DCHECK(position == TextEmphasisPosition::kUnder);
+    DCHECK(position == TextEmphasisPosition::kUnderRight ||
+           position == TextEmphasisPosition::kUnderLeft ||
+           position == TextEmphasisPosition::kOverLeft);
     emphasis_mark_offset_ = font_data->GetFontMetrics().Descent() +
                             font_.EmphasisMarkAscent(emphasis_mark);
   }
diff --git a/third_party/WebKit/Source/core/paint/ng/ng_text_fragment_painter.cc b/third_party/WebKit/Source/core/paint/ng/ng_text_fragment_painter.cc
index a08fecc..a01aeff 100644
--- a/third_party/WebKit/Source/core/paint/ng/ng_text_fragment_painter.cc
+++ b/third_party/WebKit/Source/core/paint/ng/ng_text_fragment_painter.cc
@@ -128,7 +128,7 @@
                              fragment_.IsHorizontal());
   TextEmphasisPosition emphasis_mark_position;
   bool has_text_emphasis = false;  // TODO(layout-dev): Implement.
-  emphasis_mark_position = TextEmphasisPosition::kOver;
+  emphasis_mark_position = TextEmphasisPosition::kOverRight;
   if (has_text_emphasis) {
     text_painter.SetEmphasisMark(style_to_use.TextEmphasisMarkString(),
                                  emphasis_mark_position);
diff --git a/third_party/WebKit/Source/core/style/ComputedStyleConstants.h b/third_party/WebKit/Source/core/style/ComputedStyleConstants.h
index fb5bf4b..369f533e 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyleConstants.h
+++ b/third_party/WebKit/Source/core/style/ComputedStyleConstants.h
@@ -294,6 +294,13 @@
   kSnapAlignmentCenter
 };
 
+enum TextEmphasisPosition {
+  kOverRight,
+  kOverLeft,
+  kUnderRight,
+  kUnderLeft,
+};
+
 }  // namespace blink
 
 #endif  // ComputedStyleConstants_h
diff --git a/third_party/WebKit/Source/core/testing/Internals.cpp b/third_party/WebKit/Source/core/testing/Internals.cpp
index 73193f0..b07151a 100644
--- a/third_party/WebKit/Source/core/testing/Internals.cpp
+++ b/third_party/WebKit/Source/core/testing/Internals.cpp
@@ -1169,6 +1169,33 @@
       });
 }
 
+void Internals::addSuggestionMarker(
+    const Range* range,
+    const Vector<String>& suggestions,
+    const String& suggestion_highlight_color_value,
+    const String& underline_color_value,
+    const String& thickness_value,
+    const String& background_color_value,
+    ExceptionState& exception_state) {
+  Color suggestion_highlight_color;
+  if (!ParseColor(suggestion_highlight_color_value, suggestion_highlight_color,
+                  exception_state, "Invalid suggestion highlight color."))
+    return;
+
+  DocumentMarkerController& document_marker_controller =
+      range->OwnerDocument().Markers();
+  addStyleableMarkerHelper(
+      range, underline_color_value, thickness_value, background_color_value,
+      exception_state,
+      [&document_marker_controller, &suggestions, &suggestion_highlight_color](
+          const EphemeralRange& range, Color underline_color,
+          StyleableMarker::Thickness thickness, Color background_color) {
+        document_marker_controller.AddSuggestionMarker(
+            range, suggestions, suggestion_highlight_color, underline_color,
+            thickness, background_color);
+      });
+}
+
 void Internals::setTextMatchMarkersActive(Node* node,
                                           unsigned start_offset,
                                           unsigned end_offset,
diff --git a/third_party/WebKit/Source/core/testing/Internals.h b/third_party/WebKit/Source/core/testing/Internals.h
index 89afd294..230f429 100644
--- a/third_party/WebKit/Source/core/testing/Internals.h
+++ b/third_party/WebKit/Source/core/testing/Internals.h
@@ -204,6 +204,13 @@
                                  const String& thickness_value,
                                  const String& background_color_value,
                                  ExceptionState&);
+  void addSuggestionMarker(const Range*,
+                           const Vector<String>& suggestions,
+                           const String& suggestion_highlight_color_value,
+                           const String& underline_color_value,
+                           const String& thickness_value,
+                           const String& background_color_value,
+                           ExceptionState&);
   void setTextMatchMarkersActive(Node*,
                                  unsigned start_offset,
                                  unsigned end_offset,
diff --git a/third_party/WebKit/Source/core/testing/Internals.idl b/third_party/WebKit/Source/core/testing/Internals.idl
index f22d4bb..d9a3cbb 100644
--- a/third_party/WebKit/Source/core/testing/Internals.idl
+++ b/third_party/WebKit/Source/core/testing/Internals.idl
@@ -119,6 +119,7 @@
     [RaisesException] void addTextMatchMarker(Range range, DOMString matchStatus);
     [RaisesException] void addCompositionMarker(Range range, DOMString underlineColorValue, DOMString thicknessValue, DOMString backgroundColorValue);
     [RaisesException] void addActiveSuggestionMarker(Range range, DOMString underlineColorValue, DOMString thicknessValue, DOMString backgroundColorValue);
+    [RaisesException] void addSuggestionMarker(Range range, sequence<DOMString> suggestions, DOMString suggestionHighlightColorValue, DOMString underlineColorValue, DOMString thicknessValue, DOMString backgroundColorValue);
     void setTextMatchMarkersActive(Node node, unsigned long startOffset, unsigned long endOffset, boolean active);
     void setMarkedTextMatchesAreHighlighted(Document document, boolean highlight);
 
diff --git a/third_party/WebKit/Source/devtools/front_end/performance_test_runner/TimelineTestRunner.js b/third_party/WebKit/Source/devtools/front_end/performance_test_runner/TimelineTestRunner.js
index ad30b4f..c294c9b 100644
--- a/third_party/WebKit/Source/devtools/front_end/performance_test_runner/TimelineTestRunner.js
+++ b/third_party/WebKit/Source/devtools/front_end/performance_test_runner/TimelineTestRunner.js
@@ -38,7 +38,8 @@
   thread: 'formatAsTypeName',
   allottedMilliseconds: 'formatAsTypeName',
   timedOut: 'formatAsTypeName',
-  networkTime: 'formatAsTypeName'
+  networkTime: 'formatAsTypeName',
+  timing: 'formatAsTypeName'
 };
 
 PerformanceTestRunner.InvalidationFormatters = {
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/ServiceWorkerCacheViews.js b/third_party/WebKit/Source/devtools/front_end/resources/ServiceWorkerCacheViews.js
index 1e63ffa..cd10121 100644
--- a/third_party/WebKit/Source/devtools/front_end/resources/ServiceWorkerCacheViews.js
+++ b/third_party/WebKit/Source/devtools/front_end/resources/ServiceWorkerCacheViews.js
@@ -12,6 +12,7 @@
     this.registerRequiredCSS('resources/serviceWorkerCacheViews.css');
 
     this._model = model;
+    this._entriesForTest = null;
 
     this.element.classList.add('service-worker-cache-data-view');
     this.element.classList.add('storage-view');
@@ -58,7 +59,6 @@
     this._skipCount = 0;
 
     this.update(cache);
-    this._entries = [];
   }
 
   /**
@@ -135,7 +135,7 @@
       if (!node)
         return;
     }
-    await this._model.deleteCacheEntry(this._cache, /** @type {string} */ (node.data.url));
+    await this._model.deleteCacheEntry(this._cache, /** @type {string} */ (node.data.requestURL));
     node.remove();
   }
 
@@ -155,13 +155,14 @@
 
   /**
    * @param {number} skipCount
-   * @param {!Array<!SDK.ServiceWorkerCacheModel.Entry>} entries
+   * @param {!Array<!Protocol.CacheStorage.DataEntry>} entries
    * @param {boolean} hasMore
    * @this {Resources.ServiceWorkerCacheView}
    */
   _updateDataCallback(skipCount, entries, hasMore) {
-    var selected = this._dataGrid.selectedNode && this._dataGrid.selectedNode.data.url;
+    var selected = this._dataGrid.selectedNode && this._dataGrid.selectedNode.data.requestURL;
     this._refreshButton.setEnabled(true);
+    this._entriesForTest = entries;
 
     /** @type {!Map<string, !DataGrid.DataGridNode>} */
     var oldEntries = new Map();
@@ -169,17 +170,15 @@
     for (var node of rootNode.children)
       oldEntries.set(node.data.url, node);
     rootNode.removeChildren();
-    this._entries = entries;
     var selectedNode = null;
     for (var entry of entries) {
-      var node = oldEntries.get(entry.request);
-      if (!node || node.data.timestamp !== entry.timestamp) {
-        var data = new Resources.ServiceWorkerCacheView._Response(this._cache, entry.request, entry.timestamp);
-        node = new DataGrid.DataGridNode(data);
+      var node = oldEntries.get(entry.requestURL);
+      if (!node || node.data.responseTime !== entry.responseTime) {
+        node = new Resources.ServiceWorkerCacheView.DataGridNode(entry);
         node.selectable = true;
       }
       rootNode.appendChild(node);
-      if (entry.request === selected)
+      if (entry.requestURL === selected)
         selectedNode = node;
     }
     this._pageBackButton.setEnabled(!!skipCount);
@@ -228,113 +227,76 @@
   }
 
   /**
-   * @param {!Resources.ServiceWorkerCacheView._Response} response
+   * @param {!Protocol.CacheStorage.DataEntry} entry
    */
-  async _previewCachedResponse(response) {
-    var preview = await response._previewPromise;
+  async _previewCachedResponse(entry) {
+    var preview = entry[Resources.ServiceWorkerCacheView._previewSymbol];
+    if (!preview) {
+      preview = await this._entryPreview(entry);
+      entry[Resources.ServiceWorkerCacheView._previewSymbol] = preview;
+    }
+
     // It is possible that table selection changes before the preview opens.
-    if (response === this._dataGrid.selectedNode.data)
+    if (entry === this._dataGrid.selectedNode.data)
       this._showPreview(preview);
   }
 
+  /**
+   * @param {!Protocol.CacheStorage.DataEntry} entry
+   * @return {!Promise<!UI.Widget>}
+   */
+  async _entryPreview(entry) {
+    var response = await this._cache.requestCachedResponse(entry.requestURL);
+    if (!response)
+      return new UI.EmptyWidget(Common.UIString('Preview is not available'));
+
+    var header = entry.responseHeaders.find(header => header.name.toLowerCase() === 'content-type');
+    var contentType = header ? header.value : 'text/plain';
+    var resourceType = Common.ResourceType.fromMimeType(contentType);
+    var body = resourceType.isTextType() ? window.atob(response.body) : response.body;
+    var provider = new Common.StaticContentProvider(entry.requestURL, resourceType, () => Promise.resolve(body));
+    var preview = SourceFrame.PreviewFactory.createPreview(provider, contentType);
+    if (!preview)
+      return new UI.EmptyWidget(Common.UIString('Preview is not available'));
+    return preview;
+  }
+
   _updatedForTest() {
   }
 };
 
-Resources.ServiceWorkerCacheView._Response = class {
-  /**
-   * @param {!SDK.ServiceWorkerCacheModel.Cache} cache
-   * @param {string} url
-   * @param {number} timestamp
-   */
-  constructor(cache, url, timestamp) {
-    this.url = url;
-    this.timestamp = timestamp;
-    /** @type {!Promise<!UI.Widget>} */
-    this._previewPromise = this._innerPreview(cache);
-    this.path = Resources.ServiceWorkerCacheView._Response._requestPath(url);
-    this.responseTime = new Date(timestamp * 1000).toLocaleString();
-  }
 
-  /**
-   * @param {string} url
-   * @return {string}
-   */
-  static _requestPath(url) {
-    var path = Common.ParsedURL.extractPath(url);
-    if (!path)
-      return url;
-    if (path.length > 1 && path.startsWith('/'))
-      return path.substring(1);
-    return path;
-  }
-
-  /**
-   * @param {!SDK.ServiceWorkerCacheModel.Cache} cache
-   * @return {!Promise<!UI.Widget>}
-   */
-  async _innerPreview(cache) {
-    var response = await cache.requestCachedResponse(this.url);
-    if (!response)
-      return new UI.EmptyWidget(Common.UIString('Preview is not available'));
-
-    var contentType = response.headers['content-type'];
-    var resourceType = Common.ResourceType.fromMimeType(contentType);
-    var body = resourceType.isTextType() ? window.atob(response.body) : response.body;
-    var provider = new Resources.ServiceWorkerCacheView._ResponseContentProvider(this.url, resourceType, body);
-    var preview = SourceFrame.PreviewFactory.createPreview(provider, contentType);
-    if (!preview)
-      return new UI.EmptyWidget(Common.UIString('Preview is not available'));
-    return preview;
-  }
-};
-
-/**
- * @implements {Common.ContentProvider}
- */
-Resources.ServiceWorkerCacheView._ResponseContentProvider = class {
-  /**
-   * @param {string} url
-   * @param {!Common.ResourceType} resourceType
-   * @param {string} body
-   */
-  constructor(url, resourceType, body) {
-    this._url = url;
-    this._resourceType = resourceType;
-    this._body = body;
-  }
-
-  /**
-   * @override
-   * @return {!Common.ResourceType}
-   */
-  contentType() {
-    return this._resourceType;
-  }
-
-  /**
-   * @override
-   * @return {string}
-   */
-  contentURL() {
-    return this._url;
-  }
-
-  /**
-   * @override
-   * @return {!Promise<?string>}
-   */
-  requestContent() {
-    return /** @type {!Promise<?string>} */ (Promise.resolve(this._body));
-  }
-
-  /**
-   * @override
-   * @return {!Promise<!Array<!Common.ContentProvider.SearchMatch>>}
-   */
-  searchInContent() {
-    return Promise.resolve([]);
-  }
-};
+Resources.ServiceWorkerCacheView._previewSymbol = Symbol('preview');
 
 Resources.ServiceWorkerCacheView._RESPONSE_CACHE_SIZE = 10;
+
+Resources.ServiceWorkerCacheView.DataGridNode = class extends DataGrid.DataGridNode {
+  /**
+   * @param {!Protocol.CacheStorage.DataEntry} entry
+   */
+  constructor(entry) {
+    super(entry);
+    this._path = Common.ParsedURL.extractPath(entry.requestURL);
+    if (!this._path)
+      this._path = entry.requestURL;
+    if (this._path.length > 1 && this._path.startsWith('/'))
+      this._path = this._path.substring(1);
+    this._responseTime = new Date(entry.responseTime * 1000).toLocaleString();
+  }
+
+  /**
+   * @override
+   * @param {string} columnId
+   * @return {!Element}
+   */
+  createCell(columnId) {
+    var cell = this.createTD(columnId);
+    var value;
+    if (columnId === 'path')
+      value = this._path;
+    else if (columnId === 'responseTime')
+      value = this._responseTime;
+    DataGrid.DataGrid.setElementText(cell, value || '', true);
+    return cell;
+  }
+};
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/ServiceWorkerCacheModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/ServiceWorkerCacheModel.js
index f07a3c60..fec4cb98 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/ServiceWorkerCacheModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/ServiceWorkerCacheModel.js
@@ -91,7 +91,7 @@
    * @param {!SDK.ServiceWorkerCacheModel.Cache} cache
    * @param {number} skipCount
    * @param {number} pageSize
-   * @param {function(!Array.<!SDK.ServiceWorkerCacheModel.Entry>, boolean)} callback
+   * @param {function(!Array.<!Protocol.CacheStorage.DataEntry>, boolean)} callback
    */
   loadCacheData(cache, skipCount, pageSize, callback) {
     this._requestEntries(cache, skipCount, pageSize, callback);
@@ -222,7 +222,7 @@
    * @param {!SDK.ServiceWorkerCacheModel.Cache} cache
    * @param {number} skipCount
    * @param {number} pageSize
-   * @param {function(!Array<!SDK.ServiceWorkerCacheModel.Entry>, boolean)} callback
+   * @param {function(!Array<!Protocol.CacheStorage.DataEntry>, boolean)} callback
    */
   async _requestEntries(cache, skipCount, pageSize, callback) {
     var response = await this._cacheAgent.invoke_requestEntries({cacheId: cache.cacheId, skipCount, pageSize});
@@ -230,10 +230,7 @@
       console.error('ServiceWorkerCacheAgent error while requesting entries: ', response[Protocol.Error]);
       return;
     }
-    var entries = response.cacheDataEntries.map(
-        dataEntry =>
-            new SDK.ServiceWorkerCacheModel.Entry(dataEntry.request, dataEntry.response, dataEntry.responseTime));
-    callback(entries, response.hasMore);
+    callback(response.cacheDataEntries, response.hasMore);
   }
 
   /**
@@ -273,22 +270,6 @@
 /**
  * @unrestricted
  */
-SDK.ServiceWorkerCacheModel.Entry = class {
-  /**
-   * @param {string} request
-   * @param {string} response
-   * @param {number} timestamp
-   */
-  constructor(request, response, timestamp) {
-    this.request = request;
-    this.response = response;
-    this.timestamp = timestamp;
-  }
-};
-
-/**
- * @unrestricted
- */
 SDK.ServiceWorkerCacheModel.Cache = class {
   /**
    * @param {!SDK.ServiceWorkerCacheModel} model
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/PerformanceMonitor.js b/third_party/WebKit/Source/devtools/front_end/timeline/PerformanceMonitor.js
index 864ae3f4..9af417b46 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/PerformanceMonitor.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/PerformanceMonitor.js
@@ -17,6 +17,7 @@
     this._pixelsPerMs = 20 / 1000;
     /** @const */
     this._pollIntervalMs = 500;
+    this._gridColor = 'hsla(0, 0%, 0%, 0.08)';
     this._controlPane = new Timeline.PerformanceMonitor.ControlPane(this.contentElement);
     this._canvas = /** @type {!HTMLCanvasElement} */ (this.contentElement.createChild('canvas'));
   }
@@ -26,6 +27,7 @@
    */
   wasShown() {
     this._model.enable();
+    this._startTimestamp = 0;
     this._pollTimer = setInterval(() => this._poll(), this._pollIntervalMs);
     this.onResize();
     animate.call(this);
@@ -59,21 +61,33 @@
    */
   _processMetrics(metrics) {
     var metricsMap = new Map();
-    var timestamp = Date.now();
+    var timestamp = performance.now();
     for (var metric of metrics) {
       var info = this._controlPane.metricInfo(metric.name);
       var value;
-      if (info.mode === Timeline.PerformanceMonitor.Mode.CumulativeTime) {
-        value = info.lastTimestamp ?
-            100 * Math.min(1, (metric.value - info.lastValue) * 1000 / (timestamp - info.lastTimestamp)) :
-            0;
-        info.lastValue = metric.value;
-        info.lastTimestamp = timestamp;
-      } else {
-        value = metric.value;
+      switch (info.mode) {
+        case Timeline.PerformanceMonitor.Mode.CumulativeTime:
+          value = info.lastTimestamp ?
+              100 * Number.constrain((metric.value - info.lastValue) * 1000 / (timestamp - info.lastTimestamp), 0, 1) :
+              0;
+          info.lastValue = metric.value;
+          info.lastTimestamp = timestamp;
+          break;
+        case Timeline.PerformanceMonitor.Mode.CumulativeCount:
+          value = info.lastTimestamp ?
+              Math.max(0, (metric.value - info.lastValue) * 1000 / (timestamp - info.lastTimestamp)) :
+              0;
+          info.lastValue = metric.value;
+          info.lastTimestamp = timestamp;
+          break;
+        default:
+          value = metric.value;
+          break;
       }
       metricsMap.set(metric.name, value);
     }
+    if (!this._metricsBuffer.length)
+      this._startTimestamp = timestamp;
     this._metricsBuffer.push({timestamp, metrics: metricsMap});
     var millisPerWidth = this._width / this._pixelsPerMs;
     // Multiply by 2 as the pollInterval has some jitter and to have some extra samples if window is resized.
@@ -89,9 +103,27 @@
     ctx.scale(window.devicePixelRatio, window.devicePixelRatio);
     ctx.clearRect(0, 0, this._width, this._height);
     this._drawGrid(ctx);
+    var timeMetrics = [];
+    var countMetrics = [];
     for (var metricName of this._controlPane.metrics()) {
-      if (this._controlPane.isActive(metricName))
-        this._drawMetric(ctx, metricName);
+      if (!this._controlPane.isActive(metricName))
+        continue;
+      if (this._controlPane.metricInfo(metricName).mode === Timeline.PerformanceMonitor.Mode.CumulativeTime)
+        timeMetrics.push(metricName);
+      else
+        countMetrics.push(metricName);
+    }
+
+    var timeGraphHeight = 90;
+    ctx.translate(0, 16);  // Reserve space for the scale bar.
+    if (timeMetrics.length) {
+      this._drawChart(ctx, timeMetrics, timeGraphHeight, true);
+      ctx.translate(0, timeGraphHeight);
+    }
+    var counterChartHeight = 90;
+    for (var metricName of countMetrics) {
+      this._drawChart(ctx, [metricName], counterChartHeight, false);
+      ctx.translate(0, counterChartHeight);
     }
     ctx.restore();
   }
@@ -100,56 +132,119 @@
    * @param {!CanvasRenderingContext2D} ctx
    */
   _drawGrid(ctx) {
-    var darkGray = 'hsla(0, 0%, 0%, 0.08)';
+    if (!this._startTimestamp)
+      return;
     var lightGray = 'hsla(0, 0%, 0%, 0.02)';
     ctx.font = '10px ' + Host.fontFamily();
     ctx.fillStyle = 'rgba(0, 0, 0, 0.3)';
-    for (var sec = 0;; ++sec) {
-      var x = this._width - sec * this._pixelsPerMs * 1000;
-      if (x < 0)
+    var duration = performance.now() - this._startTimestamp;
+    for (var sec = Math.floor(duration / 1000); sec >= 0; --sec) {
+      var x = this._width - (duration - sec * 1000 - this._pollIntervalMs) * this._pixelsPerMs;
+      if (x < -40)
         break;
       ctx.beginPath();
       ctx.moveTo(Math.round(x) + 0.5, 0);
       ctx.lineTo(Math.round(x) + 0.5, this._height);
       if (sec % 5 === 0)
         ctx.fillText(Common.UIString('%d sec', sec), Math.round(x) + 4, 12);
-      ctx.strokeStyle = sec % 5 ? lightGray : darkGray;
+      ctx.strokeStyle = sec % 5 ? lightGray : this._gridColor;
       ctx.stroke();
     }
+  }
+
+  /**
+   * @param {!CanvasRenderingContext2D} ctx
+   * @param {!Array<string>} metrics
+   * @param {number} height
+   * @param {boolean} smooth
+   */
+  _drawChart(ctx, metrics, height, smooth) {
+    ctx.save();
+    ctx.rect(0, 0, this._width, height);
+    ctx.clip();
+    var bottomPadding = 8;
+    var showGrid = true;
+    for (var metricName of metrics) {
+      if (!this._controlPane.isActive(metricName))
+        continue;
+      this._drawMetric(ctx, metricName, height - bottomPadding, smooth, showGrid);
+      showGrid = false;
+    }
     ctx.beginPath();
-    ctx.moveTo(0, this._height - 4.5);
-    ctx.lineTo(this._width, this._height - 4.5);
-    ctx.strokeStyle = darkGray;
+    ctx.moveTo(0, height - bottomPadding + 0.5);
+    ctx.lineTo(this._width, height - bottomPadding + 0.5);
+    ctx.strokeStyle = 'hsla(0, 0%, 0%, 0.3)';
     ctx.stroke();
+    ctx.restore();
   }
 
   /**
    * @param {!CanvasRenderingContext2D} ctx
    * @param {string} metricName
+   * @param {number} height
+   * @param {boolean} smooth
+   * @param {boolean} showGrid
    */
-  _drawMetric(ctx, metricName) {
+  _drawMetric(ctx, metricName, height, smooth, showGrid) {
+    var topPadding = 5;
+    var visibleHeight = height - topPadding;
+    if (visibleHeight < 1)
+      return;
     ctx.save();
     var width = this._width;
-    var height = this._height;
-    var startTime = Date.now() - this._pollIntervalMs * 2 - width / this._pixelsPerMs;
+    var startTime = performance.now() - this._pollIntervalMs - width / this._pixelsPerMs;
     var info = this._controlPane.metricInfo(metricName);
     var max = -Infinity;
     var pixelsPerMs = this._pixelsPerMs;
-    for (var i = this._metricsBuffer.length - 1; i >= 0; --i) {
-      var metrics = this._metricsBuffer[i];
-      var value = metrics.metrics.get(metricName);
-      max = Math.max(max, value);
-      if (metrics.timestamp < startTime)
-        break;
+    if (typeof info.max === 'number') {
+      max = info.max;
+    } else {
+      for (var i = this._metricsBuffer.length - 1; i >= 0; --i) {
+        var metrics = this._metricsBuffer[i];
+        var value = metrics.metrics.get(metricName);
+        max = Math.max(max, value);
+        if (metrics.timestamp < startTime)
+          break;
+      }
+      max = Math.max(1, max);
     }
+    var base10 = Math.pow(10, Math.floor(Math.log10(max)));
+    var leadingDigit = Math.ceil(max / base10);
+    var scaleMax = Math.ceil(leadingDigit) * base10;
+    if (leadingDigit !== 1 && leadingDigit % 2)
+      scaleMax *= 2;
+
+    max = scaleMax;
     if (isFinite(max)) {
       var alpha = 0.1;
+      max = Math.max(max, 1);
       info.currentMax = max * alpha + (info.currentMax || max) * (1 - alpha);
       max = info.currentMax;
     }
     if (typeof info.max === 'number')
       max = info.max;
-    var span = 1.2 * max || 1;
+    var span = max;
+
+    // Draw vertical grid.
+    if (showGrid) {
+      var scaleValue = scaleMax;
+      for (var i = 0; i < 2; ++i) {
+        var y = Math.round(calcY(scaleValue)) - 0.5;
+        var labelText = Timeline.PerformanceMonitor.MetricIndicator._formatNumber(scaleValue, info);
+        ctx.beginPath();
+        ctx.moveTo(0, y);
+        ctx.lineTo(4, y);
+        ctx.moveTo(ctx.measureText(labelText).width + 12, y);
+        ctx.lineTo(this._width, y);
+        ctx.strokeStyle = this._gridColor;
+        ctx.fillStyle = 'rgba(0, 0, 0, 0.3)';
+        ctx.stroke();
+        ctx.fillText(labelText, 8, calcY(scaleValue) + 3);
+        scaleValue /= 2;
+      }
+    }
+
+    // Draw chart.
     ctx.beginPath();
     ctx.moveTo(width + 5, calcY(0));
     var x = 0;
@@ -164,8 +259,13 @@
       var metrics = this._metricsBuffer[i];
       var y = calcY(metrics.metrics.get(metricName));
       x = (metrics.timestamp - startTime) * pixelsPerMs;
-      var midX = (lastX + x) / 2;
-      ctx.bezierCurveTo(midX, lastY, midX, y, x, y);
+      if (smooth) {
+        var midX = (lastX + x) / 2;
+        ctx.bezierCurveTo(midX, lastY, midX, y, x, y);
+      } else {
+        ctx.lineTo(x, lastY);
+        ctx.lineTo(x, y);
+      }
       lastX = x;
       lastY = y;
       if (metrics.timestamp < startTime)
@@ -175,8 +275,8 @@
     ctx.lineWidth = 0.5;
     ctx.stroke();
     ctx.lineTo(x, calcY(0));
-    ctx.globalAlpha = 0.02;
     ctx.fillStyle = info.color;
+    ctx.globalAlpha = 0.02;
     ctx.fill();
     ctx.restore();
 
@@ -185,7 +285,7 @@
      * @return {number}
      */
     function calcY(value) {
-      return Math.round(height - 5 - height * value / span) + 0.5;
+      return (height - visibleHeight * value / span) + 0.5;
     }
   }
 
@@ -204,7 +304,8 @@
 
 /** @enum {symbol} */
 Timeline.PerformanceMonitor.Mode = {
-  CumulativeTime: Symbol('CumulativeTime')
+  CumulativeTime: Symbol('CumulativeTime'),
+  CumulativeCount: Symbol('CumulativeCount'),
 };
 
 /**
@@ -265,11 +366,23 @@
         }
       ],
       ['NodeCount', {title: Common.UIString('DOM Nodes'), color: 'green'}],
+      ['JSEventListenerCount', {title: Common.UIString('JS event listeners'), color: 'yellowgreen'}],
       ['DocumentCount', {title: Common.UIString('Documents'), color: 'blue'}],
       ['FrameCount', {title: Common.UIString('Frames'), color: 'darkcyan'}],
-      ['JSEventListenerCount', {title: Common.UIString('JS event listeners'), color: 'yellowgreen'}],
-      ['LayoutCount', {title: Common.UIString('Layout count'), color: 'hotpink'}],
-      ['RecalcStyleCount', {title: Common.UIString('Style recalculations'), color: 'deeppink'}],
+      [
+        'LayoutCount', {
+          title: Common.UIString('Layouts / sec'),
+          color: 'hotpink',
+          mode: Timeline.PerformanceMonitor.Mode.CumulativeCount
+        }
+      ],
+      [
+        'RecalcStyleCount', {
+          title: Common.UIString('Style recalcs / sec'),
+          color: 'deeppink',
+          mode: Timeline.PerformanceMonitor.Mode.CumulativeCount
+        }
+      ],
     ]);
 
     this._indicators = new Map();
@@ -351,18 +464,20 @@
 
   /**
    * @param {number} value
+   * @param {!Timeline.PerformanceMonitor.Info} info
+   * @return {string}
+   */
+  static _formatNumber(value, info) {
+    return info.mode === Timeline.PerformanceMonitor.Mode.CumulativeTime ?
+        value.toFixed() + '%' :
+        Timeline.PerformanceMonitor.MetricIndicator._format.format(value);
+  }
+
+  /**
+   * @param {number} value
    */
   setValue(value) {
-    var textValue;
-    switch (this._info.mode) {
-      case Timeline.PerformanceMonitor.Mode.CumulativeTime:
-        textValue = value.toFixed() + '%';
-        break;
-      default:
-        textValue = new Intl.NumberFormat('en-US').format(value);
-        break;
-    }
-    this._valueElement.textContent = textValue;
+    this._valueElement.textContent = Timeline.PerformanceMonitor.MetricIndicator._formatNumber(value, this._info);
   }
 
   _toggleIndicator() {
@@ -371,3 +486,5 @@
     this._onToggle(this._active);
   }
 };
+
+Timeline.PerformanceMonitor.MetricIndicator._format = new Intl.NumberFormat('en-US', {maximumFractionDigits: 1});
diff --git a/third_party/WebKit/Source/devtools/scripts/migrate_test/move.js b/third_party/WebKit/Source/devtools/scripts/migrate_test/move.js
index 6662bf9..612fab3 100644
--- a/third_party/WebKit/Source/devtools/scripts/migrate_test/move.js
+++ b/third_party/WebKit/Source/devtools/scripts/migrate_test/move.js
@@ -18,7 +18,8 @@
 
 function main() {
   const originalTests = scanForTests([
-    '../../../../LayoutTests/inspector/elements',
+    '../../../../LayoutTests/inspector/tracing',
+    '../../../../LayoutTests/inspector/profiler',
   ]);
 
   console.log(originalTests);
diff --git a/third_party/WebKit/Source/modules/accessibility/AXObject.cpp b/third_party/WebKit/Source/modules/accessibility/AXObject.cpp
index bde9654d..a525d30 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXObject.cpp
+++ b/third_party/WebKit/Source/modules/accessibility/AXObject.cpp
@@ -833,6 +833,20 @@
   if (!event_path.size())
     return false;
 
+  // Check if the user has granted permission for this domain to use
+  // AOM event listeners yet. This may trigger an infobar, but we shouldn't
+  // block, so whatever decision the user makes will apply to the next
+  // event received after that.
+  //
+  // Note that we only ask the user about this permission the first
+  // time an event is received that actually would have triggered an
+  // event listener. However, if the user grants this permission, it
+  // persists for this origin from then on.
+  if (!AxObjectCache().CanCallAOMEventListeners()) {
+    AxObjectCache().RequestAOMEventListenerPermission();
+    return false;
+  }
+
   // Since we now know the AOM is being used in this document, get the
   // AccessibleNode for the target element and create it if necessary -
   // otherwise we wouldn't be able to set the event target. However note
diff --git a/third_party/WebKit/Source/modules/accessibility/AXObjectCacheImpl.cpp b/third_party/WebKit/Source/modules/accessibility/AXObjectCacheImpl.cpp
index c185ae3c6..61b1694 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXObjectCacheImpl.cpp
+++ b/third_party/WebKit/Source/modules/accessibility/AXObjectCacheImpl.cpp
@@ -82,8 +82,11 @@
 #include "modules/accessibility/AXTableColumn.h"
 #include "modules/accessibility/AXTableHeaderContainer.h"
 #include "modules/accessibility/AXTableRow.h"
+#include "modules/permissions/PermissionUtils.h"
 #include "platform/wtf/PassRefPtr.h"
 #include "platform/wtf/PtrUtil.h"
+#include "public/platform/modules/permissions/permission.mojom-blink.h"
+#include "public/platform/modules/permissions/permission_status.mojom-blink.h"
 #include "public/web/WebFrameClient.h"
 
 namespace blink {
@@ -96,12 +99,18 @@
 }
 
 AXObjectCacheImpl::AXObjectCacheImpl(Document& document)
-    : document_(document),
+    : AXObjectCacheBase(document),
+      document_(document),
       modification_count_(0),
       notification_post_timer_(
           TaskRunnerHelper::Get(TaskType::kUnspecedTimer, &document),
           this,
-          &AXObjectCacheImpl::NotificationPostTimerFired) {}
+          &AXObjectCacheImpl::NotificationPostTimerFired),
+      accessibility_event_permission_(mojom::PermissionStatus::ASK),
+      permission_observer_binding_(this) {
+  if (document_->LoadEventFinished())
+    AddPermissionStatusListener();
+}
 
 AXObjectCacheImpl::~AXObjectCacheImpl() {
 #if DCHECK_IS_ON()
@@ -1214,6 +1223,7 @@
 
 void AXObjectCacheImpl::HandleLoadComplete(Document* document) {
   PostNotification(GetOrCreate(document), AXObjectCache::kAXLoadComplete);
+  AddPermissionStatusListener();
 }
 
 void AXObjectCacheImpl::HandleLayoutComplete(Document* document) {
@@ -1287,6 +1297,52 @@
   obj->SetElementRect(rect, ax_canvas);
 }
 
+void AXObjectCacheImpl::AddPermissionStatusListener() {
+  if (!document_->GetExecutionContext())
+    return;
+
+  ConnectToPermissionService(document_->GetExecutionContext(),
+                             mojo::MakeRequest(&permission_service_));
+
+  if (permission_observer_binding_.is_bound())
+    permission_observer_binding_.Close();
+
+  mojom::blink::PermissionObserverPtr observer;
+  permission_observer_binding_.Bind(mojo::MakeRequest(&observer));
+  permission_service_->AddPermissionObserver(
+      CreatePermissionDescriptor(
+          mojom::blink::PermissionName::ACCESSIBILITY_EVENTS),
+      document_->GetExecutionContext()->GetSecurityOrigin(),
+      accessibility_event_permission_, std::move(observer));
+}
+
+void AXObjectCacheImpl::OnPermissionStatusChange(
+    mojom::PermissionStatus status) {
+  accessibility_event_permission_ = status;
+}
+
+bool AXObjectCacheImpl::CanCallAOMEventListeners() const {
+  return accessibility_event_permission_ == mojom::PermissionStatus::GRANTED;
+}
+
+void AXObjectCacheImpl::RequestAOMEventListenerPermission() {
+  if (accessibility_event_permission_ != mojom::PermissionStatus::ASK)
+    return;
+
+  permission_service_->RequestPermission(
+      CreatePermissionDescriptor(
+          mojom::blink::PermissionName::ACCESSIBILITY_EVENTS),
+      document_->GetExecutionContext()->GetSecurityOrigin(),
+      UserGestureIndicator::ProcessingUserGesture(),
+      ConvertToBaseCallback(WTF::Bind(
+          &AXObjectCacheImpl::OnPermissionStatusChange, WrapPersistent(this))));
+}
+
+void AXObjectCacheImpl::ContextDestroyed(ExecutionContext*) {
+  permission_service_.reset();
+  permission_observer_binding_.Close();
+}
+
 DEFINE_TRACE(AXObjectCacheImpl) {
   visitor->Trace(document_);
   visitor->Trace(node_object_mapping_);
diff --git a/third_party/WebKit/Source/modules/accessibility/AXObjectCacheImpl.h b/third_party/WebKit/Source/modules/accessibility/AXObjectCacheImpl.h
index b8844f4..ed99342 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXObjectCacheImpl.h
+++ b/third_party/WebKit/Source/modules/accessibility/AXObjectCacheImpl.h
@@ -31,11 +31,15 @@
 
 #include <memory>
 #include "core/dom/AXObjectCacheBase.h"
+#include "core/dom/ContextLifecycleObserver.h"
 #include "modules/ModulesExport.h"
 #include "modules/accessibility/AXObject.h"
+#include "mojo/public/cpp/bindings/binding.h"
 #include "platform/wtf/Forward.h"
 #include "platform/wtf/HashMap.h"
 #include "platform/wtf/HashSet.h"
+#include "public/platform/modules/permissions/permission.mojom-blink.h"
+#include "public/platform/modules/permissions/permission_status.mojom-blink.h"
 
 namespace blink {
 
@@ -44,7 +48,9 @@
 class LocalFrameView;
 
 // This class should only be used from inside the accessibility directory.
-class MODULES_EXPORT AXObjectCacheImpl : public AXObjectCacheBase {
+class MODULES_EXPORT AXObjectCacheImpl
+    : public AXObjectCacheBase,
+      public mojom::blink::PermissionObserver {
   WTF_MAKE_NONCOPYABLE(AXObjectCacheImpl);
 
  public:
@@ -190,6 +196,16 @@
   // potential owner, possibly reparenting this element.
   void UpdateTreeIfElementIdIsAriaOwned(Element*);
 
+  // Synchronously returns whether or not we currently have permission to
+  // call AOM event listeners.
+  bool CanCallAOMEventListeners() const;
+
+  // This is called when an accessibility event is triggered and there are
+  // AOM event listeners registered that would have been called.
+  // Asynchronously requests permission from the user. If permission is
+  // granted, it only applies to the next event received.
+  void RequestAOMEventListenerPermission();
+
  protected:
   void PostPlatformNotification(AXObject*, AXNotification);
   void LabelChanged(Element*);
@@ -249,6 +265,9 @@
       notifications_to_post_;
   void NotificationPostTimerFired(TimerBase*);
 
+  // ContextLifecycleObserver overrides.
+  void ContextDestroyed(ExecutionContext*) override;
+
   AXObject* FocusedImageMapUIElement(HTMLAreaElement*);
 
   AXID GetOrCreateAXID(AXObject*);
@@ -258,6 +277,22 @@
   AXObject* NearestExistingAncestor(Node*);
 
   Settings* GetSettings();
+
+  // Start listenening for updates to the AOM accessibility event permission.
+  void AddPermissionStatusListener();
+
+  // mojom::blink::PermissionObserver implementation.
+  // Called when we get an updated AOM event listener permission value from
+  // the browser.
+  void OnPermissionStatusChange(mojom::PermissionStatus);
+
+  // Whether the user has granted permission for the user to install event
+  // listeners for accessibility events using the AOM.
+  mojom::PermissionStatus accessibility_event_permission_;
+  // The permission service, enabling us to check for event listener
+  // permission.
+  mojom::blink::PermissionServicePtr permission_service_;
+  mojo::Binding<mojom::blink::PermissionObserver> permission_observer_binding_;
 };
 
 // This is the only subclass of AXObjectCache.
diff --git a/third_party/WebKit/Source/modules/accessibility/DEPS b/third_party/WebKit/Source/modules/accessibility/DEPS
index f0b9b68e..81fd1cd 100644
--- a/third_party/WebKit/Source/modules/accessibility/DEPS
+++ b/third_party/WebKit/Source/modules/accessibility/DEPS
@@ -3,4 +3,6 @@
     "+modules/ModulesExport.h",
     "+modules/accessibility",
     "+modules/media_controls",
+    "+modules/permissions",
+    "+mojo/public/cpp/bindings/binding.h",
 ]
diff --git a/third_party/WebKit/Source/modules/cachestorage/InspectorCacheStorageAgent.cpp b/third_party/WebKit/Source/modules/cachestorage/InspectorCacheStorageAgent.cpp
index 4b1940c..87da598 100644
--- a/third_party/WebKit/Source/modules/cachestorage/InspectorCacheStorageAgent.cpp
+++ b/third_party/WebKit/Source/modules/cachestorage/InspectorCacheStorageAgent.cpp
@@ -45,6 +45,7 @@
 using blink::protocol::CacheStorage::Cache;
 using blink::protocol::CacheStorage::CachedResponse;
 using blink::protocol::CacheStorage::DataEntry;
+using blink::protocol::CacheStorage::Header;
 // Renaming Response since there is another blink::Response.
 using ProtocolResponse = blink::protocol::Response;
 
@@ -203,12 +204,9 @@
 };
 
 struct RequestResponse {
-  RequestResponse() {}
-  RequestResponse(const String& request, const String& response)
-      : request(request), response(response) {}
-  String request;
-  String response;
+  String request_url;
   double response_time;
+  Vector<std::pair<String, String>> headers;
 };
 
 class ResponsesAccumulator : public RefCounted<ResponsesAccumulator> {
@@ -228,16 +226,20 @@
     DCHECK_GT(num_responses_left_, 0);
     RequestResponse& request_response =
         responses_.at(responses_.size() - num_responses_left_);
-    request_response.request = request.Url().GetString();
-    request_response.response = response.StatusText();
+    request_response.request_url = request.Url().GetString();
     request_response.response_time = response.ResponseTime().ToDoubleT();
+    for (const auto& header : response.GetHeaderKeys()) {
+      request_response.headers.push_back(
+          std::make_pair(header, response.GetHeader(header)));
+    }
 
     if (--num_responses_left_ != 0)
       return;
 
     std::sort(responses_.begin(), responses_.end(),
               [](const RequestResponse& a, const RequestResponse& b) {
-                return WTF::CodePointCompareLessThan(a.request, b.request);
+                return WTF::CodePointCompareLessThan(a.request_url,
+                                                     b.request_url);
               });
     if (params_.skip_count > 0)
       responses_.erase(0, params_.skip_count);
@@ -249,11 +251,18 @@
     }
     std::unique_ptr<Array<DataEntry>> array = Array<DataEntry>::create();
     for (const auto& request_response : responses_) {
+      std::unique_ptr<Array<Header>> headers = Array<Header>::create();
+      for (const auto& header : request_response.headers) {
+        headers->addItem(Header::create()
+                             .setName(header.first)
+                             .setValue(header.second)
+                             .build());
+      }
       std::unique_ptr<DataEntry> entry =
           DataEntry::create()
-              .setRequest(request_response.request)
-              .setResponse(request_response.response)
+              .setRequestURL(request_response.request_url)
               .setResponseTime(request_response.response_time)
+              .setResponseHeaders(std::move(headers))
               .build();
       array->addItem(std::move(entry));
     }
@@ -458,11 +467,10 @@
 
  public:
   static void Load(ExecutionContext* context,
-                   std::unique_ptr<protocol::DictionaryValue> headers,
                    PassRefPtr<BlobDataHandle> blob,
                    std::unique_ptr<RequestCachedResponseCallback> callback) {
-    new CachedResponseFileReaderLoaderClient(
-        context, std::move(headers), std::move(blob), std::move(callback));
+    new CachedResponseFileReaderLoaderClient(context, std::move(blob),
+                                             std::move(callback));
   }
 
   void DidStartLoading() override {}
@@ -470,7 +478,6 @@
   void DidFinishLoading() override {
     std::unique_ptr<CachedResponse> response =
         CachedResponse::create()
-            .setHeaders(std::move(headers_))
             .setBody(Base64Encode(data_->Data(), data_->size()))
             .build();
     callback_->sendSuccess(std::move(response));
@@ -491,13 +498,11 @@
  private:
   CachedResponseFileReaderLoaderClient(
       ExecutionContext* context,
-      std::unique_ptr<protocol::DictionaryValue>&& headers,
       PassRefPtr<BlobDataHandle>&& blob,
       std::unique_ptr<RequestCachedResponseCallback>&& callback)
       : loader_(
             FileReaderLoader::Create(FileReaderLoader::kReadByClient, this)),
         callback_(std::move(callback)),
-        headers_(std::move(headers)),
         data_(SharedBuffer::Create()) {
     loader_->Start(context, std::move(blob));
   }
@@ -508,7 +513,6 @@
 
   std::unique_ptr<FileReaderLoader> loader_;
   std::unique_ptr<RequestCachedResponseCallback> callback_;
-  std::unique_ptr<protocol::DictionaryValue> headers_;
   RefPtr<SharedBuffer> data_;
 };
 
@@ -527,14 +531,12 @@
         protocol::DictionaryValue::create();
     if (!response.GetBlobDataHandle()) {
       callback_->sendSuccess(CachedResponse::create()
-                                 .setHeaders(ToHeadersDictionary(response))
                                  .setBody("")
                                  .build());
       return;
     }
     CachedResponseFileReaderLoaderClient::Load(
-        context_, ToHeadersDictionary(response), response.GetBlobDataHandle(),
-        std::move(callback_));
+        context_, response.GetBlobDataHandle(), std::move(callback_));
   }
 
   void OnError(WebServiceWorkerCacheError error) override {
@@ -544,14 +546,6 @@
   }
 
  private:
-  static std::unique_ptr<protocol::DictionaryValue> ToHeadersDictionary(
-      const WebServiceWorkerResponse& response) {
-    auto headers = protocol::DictionaryValue::create();
-    for (const auto& header : response.GetHeaderKeys())
-      headers->setString(header, response.GetHeader(header));
-    return headers;
-  }
-
   std::unique_ptr<RequestCachedResponseCallback> callback_;
   Persistent<ExecutionContext> context_;
 };
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBDatabase.cpp b/third_party/WebKit/Source/modules/indexeddb/IDBDatabase.cpp
index 04ee6dd..16df2f1 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBDatabase.cpp
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBDatabase.cpp
@@ -126,6 +126,13 @@
   ContextLifecycleObserver::Trace(visitor);
 }
 
+DEFINE_TRACE_WRAPPERS(IDBDatabase) {
+  for (const auto& observer : observers_.Values()) {
+    visitor->TraceWrappers(observer);
+  }
+  EventTargetWithInlineData::TraceWrappers(visitor);
+}
+
 int64_t IDBDatabase::NextTransactionId() {
   // Only keep a 32-bit counter to allow ports to use the other 32
   // bits of the id.
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBDatabase.h b/third_party/WebKit/Source/modules/indexeddb/IDBDatabase.h
index d4515ce..de8d7b9 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBDatabase.h
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBDatabase.h
@@ -43,6 +43,7 @@
 #include "modules/indexeddb/IndexedDB.h"
 #include "platform/bindings/ActiveScriptWrappable.h"
 #include "platform/bindings/ScriptState.h"
+#include "platform/bindings/TraceWrapperMember.h"
 #include "platform/heap/Handle.h"
 #include "platform/wtf/RefPtr.h"
 #include "public/platform/modules/indexeddb/WebIDBDatabase.h"
@@ -69,6 +70,7 @@
                              v8::Isolate*);
   ~IDBDatabase() override;
   DECLARE_VIRTUAL_TRACE();
+  DECLARE_VIRTUAL_TRACE_WRAPPERS();
 
   // Overwrites the database metadata, including object store and index
   // metadata. Used to pass metadata to the database when it is opened.
@@ -191,7 +193,7 @@
   std::unique_ptr<WebIDBDatabase> backend_;
   Member<IDBTransaction> version_change_transaction_;
   HeapHashMap<int64_t, Member<IDBTransaction>> transactions_;
-  HeapHashMap<int32_t, Member<IDBObserver>> observers_;
+  HeapHashMap<int32_t, TraceWrapperMember<IDBObserver>> observers_;
 
   bool close_pending_ = false;
 
diff --git a/third_party/WebKit/Source/modules/permissions/PermissionDescriptor.idl b/third_party/WebKit/Source/modules/permissions/PermissionDescriptor.idl
index 80735f0..3ce943f3 100644
--- a/third_party/WebKit/Source/modules/permissions/PermissionDescriptor.idl
+++ b/third_party/WebKit/Source/modules/permissions/PermissionDescriptor.idl
@@ -12,6 +12,7 @@
     "accelerometer",
     "gyroscope",
     "magnetometer",
+    "accessibility-events",
 };
 
 // The PermissionDescriptor dictionary is a base to describe permissions. Some
diff --git a/third_party/WebKit/Source/modules/permissions/Permissions.cpp b/third_party/WebKit/Source/modules/permissions/Permissions.cpp
index b30cfc6..1dfa8757 100644
--- a/third_party/WebKit/Source/modules/permissions/Permissions.cpp
+++ b/third_party/WebKit/Source/modules/permissions/Permissions.cpp
@@ -112,6 +112,14 @@
 
     return CreatePermissionDescriptor(PermissionName::SENSORS);
   }
+  if (name == "accessibility-events") {
+    if (!RuntimeEnabledFeatures::AccessibilityObjectModelEnabled()) {
+      exception_state.ThrowTypeError(
+          "Accessibility Object Model is not enabled.");
+      return nullptr;
+    }
+    return CreatePermissionDescriptor(PermissionName::ACCESSIBILITY_EVENTS);
+  }
 
   return nullptr;
 }
diff --git a/third_party/WebKit/Source/modules/webaudio/BaseAudioContextTest.cpp b/third_party/WebKit/Source/modules/webaudio/BaseAudioContextTest.cpp
index 0b90ac2..4ed07b29 100644
--- a/third_party/WebKit/Source/modules/webaudio/BaseAudioContextTest.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/BaseAudioContextTest.cpp
@@ -95,14 +95,15 @@
 
 }  // anonymous namespace
 
-#if defined(OS_ANDROID) && defined(ADDRESS_SANITIZER)
+#if defined(OS_ANDROID)
 // Often times out with Android ASAN: https://crbug.com/758934.
-#define MAYBE_BaseAudioContextAutoplayTest DISABLED_BaseAudioContextAutoplayTest
+#define MAYBE_TEST_P(test_case_name, test_name) \
+  TEST_P(test_case_name, DISABLED_##test_name)
 #else
-#define MAYBE_BaseAudioContextAutoplayTest BaseAudioContextAutoplayTest
+#define MAYBE_TEST_P TEST_P
 #endif
 
-class MAYBE_BaseAudioContextAutoplayTest
+class BaseAudioContextAutoplayTest
     : public ::testing::TestWithParam<AutoplayPolicy::Type> {
  protected:
   using AutoplayStatus = BaseAudioContext::AutoplayStatus;
@@ -170,8 +171,8 @@
 };
 
 // Creates an AudioContext without a gesture inside a x-origin child frame.
-TEST_P(MAYBE_BaseAudioContextAutoplayTest,
-       AutoplayMetrics_CreateNoGesture_Child) {
+MAYBE_TEST_P(BaseAudioContextAutoplayTest,
+             AutoplayMetrics_CreateNoGesture_Child) {
   BaseAudioContext* audio_context = BaseAudioContext::Create(
       ChildDocument(), AudioContextOptions(), ASSERT_NO_EXCEPTION);
   RecordAutoplayStatus(audio_context);
@@ -195,8 +196,8 @@
 }
 
 // Creates an AudioContext without a gesture inside a main frame.
-TEST_P(MAYBE_BaseAudioContextAutoplayTest,
-       AutoplayMetrics_CreateNoGesture_Main) {
+MAYBE_TEST_P(BaseAudioContextAutoplayTest,
+             AutoplayMetrics_CreateNoGesture_Main) {
   BaseAudioContext* audio_context = BaseAudioContext::Create(
       GetDocument(), AudioContextOptions(), ASSERT_NO_EXCEPTION);
   RecordAutoplayStatus(audio_context);
@@ -219,8 +220,8 @@
 
 // Creates an AudioContext then call resume without a gesture in a x-origin
 // child frame.
-TEST_P(MAYBE_BaseAudioContextAutoplayTest,
-       AutoplayMetrics_CallResumeNoGesture_Child) {
+MAYBE_TEST_P(BaseAudioContextAutoplayTest,
+             AutoplayMetrics_CallResumeNoGesture_Child) {
   ScriptState::Scope scope(GetScriptStateFrom(ChildDocument()));
 
   BaseAudioContext* audio_context = BaseAudioContext::Create(
@@ -248,8 +249,8 @@
 }
 
 // Creates an AudioContext then call resume without a gesture in a main frame.
-TEST_P(MAYBE_BaseAudioContextAutoplayTest,
-       AutoplayMetrics_CallResumeNoGesture_Main) {
+MAYBE_TEST_P(BaseAudioContextAutoplayTest,
+             AutoplayMetrics_CallResumeNoGesture_Main) {
   ScriptState::Scope scope(GetScriptStateFrom(GetDocument()));
 
   BaseAudioContext* audio_context = BaseAudioContext::Create(
@@ -275,8 +276,8 @@
 }
 
 // Creates an AudioContext with a user gesture inside a x-origin child frame.
-TEST_P(MAYBE_BaseAudioContextAutoplayTest,
-       AutoplayMetrics_CreateGesture_Child) {
+MAYBE_TEST_P(BaseAudioContextAutoplayTest,
+             AutoplayMetrics_CreateGesture_Child) {
   std::unique_ptr<UserGestureIndicator> user_gesture_scope =
       LocalFrame::CreateUserGesture(ChildDocument().GetFrame(),
                                     UserGestureToken::kNewGesture);
@@ -305,7 +306,7 @@
 }
 
 // Creates an AudioContext with a user gesture inside a main frame.
-TEST_P(MAYBE_BaseAudioContextAutoplayTest, AutoplayMetrics_CreateGesture_Main) {
+MAYBE_TEST_P(BaseAudioContextAutoplayTest, AutoplayMetrics_CreateGesture_Main) {
   std::unique_ptr<UserGestureIndicator> user_gesture_scope =
       LocalFrame::CreateUserGesture(GetDocument().GetFrame(),
                                     UserGestureToken::kNewGesture);
@@ -332,8 +333,8 @@
 
 // Creates an AudioContext then calls resume with a user gesture inside a
 // x-origin child frame.
-TEST_P(MAYBE_BaseAudioContextAutoplayTest,
-       AutoplayMetrics_CallResumeGesture_Child) {
+MAYBE_TEST_P(BaseAudioContextAutoplayTest,
+             AutoplayMetrics_CallResumeGesture_Child) {
   ScriptState::Scope scope(GetScriptStateFrom(ChildDocument()));
 
   BaseAudioContext* audio_context = BaseAudioContext::Create(
@@ -368,8 +369,8 @@
 
 // Creates an AudioContext then calls resume with a user gesture inside a main
 // frame.
-TEST_P(MAYBE_BaseAudioContextAutoplayTest,
-       AutoplayMetrics_CallResumeGesture_Main) {
+MAYBE_TEST_P(BaseAudioContextAutoplayTest,
+             AutoplayMetrics_CallResumeGesture_Main) {
   ScriptState::Scope scope(GetScriptStateFrom(GetDocument()));
 
   BaseAudioContext* audio_context = BaseAudioContext::Create(
@@ -401,8 +402,8 @@
 
 // Creates an AudioContext then calls start on a node without a gesture inside a
 // x-origin child frame.
-TEST_P(MAYBE_BaseAudioContextAutoplayTest,
-       AutoplayMetrics_NodeStartNoGesture_Child) {
+MAYBE_TEST_P(BaseAudioContextAutoplayTest,
+             AutoplayMetrics_NodeStartNoGesture_Child) {
   BaseAudioContext* audio_context = BaseAudioContext::Create(
       ChildDocument(), AudioContextOptions(), ASSERT_NO_EXCEPTION);
   audio_context->MaybeRecordStartAttempt();
@@ -428,8 +429,8 @@
 
 // Creates an AudioContext then calls start on a node without a gesture inside a
 // main frame.
-TEST_P(MAYBE_BaseAudioContextAutoplayTest,
-       AutoplayMetrics_NodeStartNoGesture_Main) {
+MAYBE_TEST_P(BaseAudioContextAutoplayTest,
+             AutoplayMetrics_NodeStartNoGesture_Main) {
   BaseAudioContext* audio_context = BaseAudioContext::Create(
       GetDocument(), AudioContextOptions(), ASSERT_NO_EXCEPTION);
   audio_context->MaybeRecordStartAttempt();
@@ -453,8 +454,8 @@
 
 // Creates an AudioContext then calls start on a node with a gesture inside a
 // x-origin child frame.
-TEST_P(MAYBE_BaseAudioContextAutoplayTest,
-       AutoplayMetrics_NodeStartGesture_Child) {
+MAYBE_TEST_P(BaseAudioContextAutoplayTest,
+             AutoplayMetrics_NodeStartGesture_Child) {
   BaseAudioContext* audio_context = BaseAudioContext::Create(
       ChildDocument(), AudioContextOptions(), ASSERT_NO_EXCEPTION);
 
@@ -485,8 +486,8 @@
 
 // Creates an AudioContext then calls start on a node with a gesture inside a
 // main frame.
-TEST_P(MAYBE_BaseAudioContextAutoplayTest,
-       AutoplayMetrics_NodeStartGesture_Main) {
+MAYBE_TEST_P(BaseAudioContextAutoplayTest,
+             AutoplayMetrics_NodeStartGesture_Main) {
   BaseAudioContext* audio_context = BaseAudioContext::Create(
       GetDocument(), AudioContextOptions(), ASSERT_NO_EXCEPTION);
 
@@ -514,8 +515,8 @@
 
 // Creates an AudioContext then calls start on a node without a gesture and
 // finally allows the AudioContext to produce sound inside x-origin child frame.
-TEST_P(MAYBE_BaseAudioContextAutoplayTest,
-       AutoplayMetrics_NodeStartNoGestureThenSuccess_Child) {
+MAYBE_TEST_P(BaseAudioContextAutoplayTest,
+             AutoplayMetrics_NodeStartNoGestureThenSuccess_Child) {
   ScriptState::Scope scope(GetScriptStateFrom(ChildDocument()));
 
   BaseAudioContext* audio_context = BaseAudioContext::Create(
@@ -550,8 +551,8 @@
 
 // Creates an AudioContext then calls start on a node without a gesture and
 // finally allows the AudioContext to produce sound inside a main frame.
-TEST_P(MAYBE_BaseAudioContextAutoplayTest,
-       AutoplayMetrics_NodeStartNoGestureThenSuccess_Main) {
+MAYBE_TEST_P(BaseAudioContextAutoplayTest,
+             AutoplayMetrics_NodeStartNoGestureThenSuccess_Main) {
   ScriptState::Scope scope(GetScriptStateFrom(GetDocument()));
 
   BaseAudioContext* audio_context = BaseAudioContext::Create(
@@ -583,8 +584,8 @@
 
 // Creates an AudioContext then calls start on a node with a gesture and
 // finally allows the AudioContext to produce sound inside x-origin child frame.
-TEST_P(MAYBE_BaseAudioContextAutoplayTest,
-       AutoplayMetrics_NodeStartGestureThenSucces_Child) {
+MAYBE_TEST_P(BaseAudioContextAutoplayTest,
+             AutoplayMetrics_NodeStartGestureThenSucces_Child) {
   ScriptState::Scope scope(GetScriptStateFrom(ChildDocument()));
 
   BaseAudioContext* audio_context = BaseAudioContext::Create(
@@ -619,8 +620,8 @@
 
 // Creates an AudioContext then calls start on a node with a gesture and
 // finally allows the AudioContext to produce sound inside a main frame.
-TEST_P(MAYBE_BaseAudioContextAutoplayTest,
-       AutoplayMetrics_NodeStartGestureThenSucces_Main) {
+MAYBE_TEST_P(BaseAudioContextAutoplayTest,
+             AutoplayMetrics_NodeStartGestureThenSucces_Main) {
   ScriptState::Scope scope(GetScriptStateFrom(GetDocument()));
 
   BaseAudioContext* audio_context = BaseAudioContext::Create(
@@ -652,8 +653,8 @@
 
 // Attempts to autoplay an AudioContext in a x-origin child frame when the
 // document previous received a user gesture.
-TEST_P(MAYBE_BaseAudioContextAutoplayTest,
-       AutoplayMetrics_DocumentReceivedGesture_Child) {
+MAYBE_TEST_P(BaseAudioContextAutoplayTest,
+             AutoplayMetrics_DocumentReceivedGesture_Child) {
   ChildDocument().GetFrame()->UpdateUserActivationInFrameTree();
 
   BaseAudioContext* audio_context = BaseAudioContext::Create(
@@ -688,8 +689,8 @@
 
 // Attempts to autoplay an AudioContext in a main child frame when the
 // document previous received a user gesture.
-TEST_P(MAYBE_BaseAudioContextAutoplayTest,
-       AutoplayMetrics_DocumentReceivedGesture_Main) {
+MAYBE_TEST_P(BaseAudioContextAutoplayTest,
+             AutoplayMetrics_DocumentReceivedGesture_Main) {
   GetDocument().GetFrame()->UpdateUserActivationInFrameTree();
 
   BaseAudioContext* audio_context = BaseAudioContext::Create(
@@ -714,8 +715,8 @@
 
 // Attempts to autoplay an AudioContext in a main child frame when the
 // document received a user gesture before navigation.
-TEST_P(MAYBE_BaseAudioContextAutoplayTest,
-       AutoplayMetrics_DocumentReceivedGesture_BeforeNavigation) {
+MAYBE_TEST_P(BaseAudioContextAutoplayTest,
+             AutoplayMetrics_DocumentReceivedGesture_BeforeNavigation) {
   GetDocument().GetFrame()->SetDocumentHasReceivedUserGestureBeforeNavigation(
       true);
 
@@ -740,8 +741,8 @@
 }
 
 INSTANTIATE_TEST_CASE_P(
-    MAYBE_BaseAudioContextAutoplayTest,
-    MAYBE_BaseAudioContextAutoplayTest,
+    BaseAudioContextAutoplayTest,
+    BaseAudioContextAutoplayTest,
     ::testing::Values(AutoplayPolicy::Type::kNoUserGestureRequired,
                       AutoplayPolicy::Type::kUserGestureRequired,
                       AutoplayPolicy::Type::kUserGestureRequiredForCrossOrigin,
diff --git a/third_party/WebKit/Source/platform/feature_policy/FeaturePolicy.cpp b/third_party/WebKit/Source/platform/feature_policy/FeaturePolicy.cpp
index e83576a7..ab9d06e7 100644
--- a/third_party/WebKit/Source/platform/feature_policy/FeaturePolicy.cpp
+++ b/third_party/WebKit/Source/platform/feature_policy/FeaturePolicy.cpp
@@ -8,73 +8,166 @@
 #include "platform/json/JSONValues.h"
 #include "platform/network/HTTPParsers.h"
 #include "platform/weborigin/SecurityOrigin.h"
+#include "platform/wtf/ASCIICType.h"
+#include "platform/wtf/BitVector.h"
 #include "platform/wtf/PtrUtil.h"
+#include "platform/wtf/text/ParsingUtilities.h"
 
 namespace blink {
 
-WebParsedFeaturePolicy ParseFeaturePolicy(const String& policy,
-                                          RefPtr<SecurityOrigin> origin,
-                                          Vector<String>* messages) {
-  return ParseFeaturePolicy(policy, origin, messages,
+namespace {
+// TODO(lunalu): Deprecate the methods in this namesapce when deprecating old
+// allow syntax.
+bool IsValidOldAllowSyntax(const String& policy,
+                           RefPtr<SecurityOrigin> src_origin) {
+  // Old syntax enable all features on src_origin, If src_origin does not exist
+  // (example, http header does not have a src_origin), then the syntax cannot
+  // be valid.
+  if (!src_origin)
+    return false;
+  // allow = "feature" is also supported by new syntax.
+  if (!policy.Contains(' '))
+    return false;
+  // Old syntax only allows whitespace as valid delimiter.
+  if (policy.Contains(';') || policy.Contains(','))
+    return false;
+  // Old syntax does not support specifying wildcards / origins for any feature.
+  if (policy.Contains("self") || policy.Contains("src") ||
+      policy.Contains("none") || policy.Contains("*")) {
+    return false;
+  }
+
+  // Verify that the policy follows this syntax:
+  //     allow = "name1 name2 name3 ...", name* = 1*( ALPHA / DIGIT / "-" )
+  auto IsValidFeatureNameCharacter = [](auto c) {
+    return IsASCIIAlphanumeric(c) || c == '-';
+  };
+
+  for (unsigned i = 0; i < policy.length(); i++) {
+    if (!IsValidFeatureNameCharacter(policy[i]) && !IsASCIISpace(policy[i]))
+      return false;
+  }
+  return true;
+}
+
+Vector<WebParsedFeaturePolicyDeclaration> ParseOldAllowSyntax(
+    const String& policy,
+    RefPtr<SecurityOrigin> origin,
+    Vector<String>* messages,
+    const FeatureNameMap& feature_names) {
+  Vector<WebParsedFeaturePolicyDeclaration> whitelists;
+  if (messages) {
+    messages->push_back(
+        "The old syntax (allow=\"feature1 feature2 feature3 ...\") will soon "
+        "be deprecated");
+  }
+  Vector<String> tokens;
+  policy.Split(' ', tokens);
+  for (const String& token : tokens) {
+    if (!feature_names.Contains(token)) {
+      if (messages)
+        messages->push_back("Unrecognized feature: '" + token + "'.");
+      continue;
+    }
+    WebParsedFeaturePolicyDeclaration whitelist;
+    whitelist.feature = feature_names.at(token);
+    whitelist.origins = Vector<WebSecurityOrigin>(1UL, {origin});
+    whitelists.push_back(whitelist);
+  }
+  return whitelists;
+}
+
+}  // namespace
+
+WebParsedFeaturePolicy ParseFeaturePolicyHeader(const String& policy,
+                                                RefPtr<SecurityOrigin> origin,
+                                                Vector<String>* messages) {
+  return ParseFeaturePolicy(policy, origin, RefPtr<SecurityOrigin>(), messages,
                             GetDefaultFeatureNameMap());
 }
 
-WebParsedFeaturePolicy ParseFeaturePolicy(const String& policy,
-                                          RefPtr<SecurityOrigin> origin,
-                                          Vector<String>* messages,
-                                          const FeatureNameMap& feature_names) {
+Vector<WebParsedFeaturePolicyDeclaration> ParseFeaturePolicyAttribute(
+    const String& policy,
+    RefPtr<SecurityOrigin> self_origin,
+    RefPtr<SecurityOrigin> src_origin,
+    Vector<String>* messages) {
+  return ParseFeaturePolicy(policy, self_origin, src_origin, messages,
+                            GetDefaultFeatureNameMap());
+}
+
+Vector<WebParsedFeaturePolicyDeclaration> ParseFeaturePolicy(
+    const String& policy,
+    RefPtr<SecurityOrigin> self_origin,
+    RefPtr<SecurityOrigin> src_origin,
+    Vector<String>* messages,
+    const FeatureNameMap& feature_names) {
+  // Temporarily supporting old allow syntax:
+  //     allow = "feature1 feature2 feature3 ... "
+  // TODO(lunalu): depracate this old syntax in the future.
+  if (IsValidOldAllowSyntax(policy, src_origin))
+    return ParseOldAllowSyntax(policy, src_origin, messages, feature_names);
+
   Vector<WebParsedFeaturePolicyDeclaration> whitelists;
+  BitVector features_specified(
+      static_cast<int>(WebFeaturePolicyFeature::LAST_FEATURE));
 
-  // Use a reasonable parse depth limit; the actual maximum depth is only going
-  // to be 4 for a valid policy, but we'll give the featurePolicyParser a chance
-  // to report more specific errors, unless the string is really invalid.
-  std::unique_ptr<JSONArray> policy_items = ParseJSONHeader(policy, 50);
-  if (!policy_items) {
-    if (messages)
-      messages->push_back("Unable to parse header.");
-    return whitelists;
-  }
-
-  for (size_t i = 0; i < policy_items->size(); ++i) {
-    JSONObject* item = JSONObject::Cast(policy_items->at(i));
-    if (!item) {
-      if (messages)
-        messages->push_back("Policy is not an object.");
-      continue;  // Array element is not an object; skip
-    }
-
-    for (size_t j = 0; j < item->size(); ++j) {
-      JSONObject::Entry entry = item->at(j);
-      if (!feature_names.Contains(entry.first))
-        continue;  // Unrecognized feature; skip
-      WebFeaturePolicyFeature feature = feature_names.at(entry.first);
-      JSONArray* targets = JSONArray::Cast(entry.second);
-      if (!targets) {
+  // RFC2616, section 4.2 specifies that headers appearing multiple times can be
+  // combined with a comma. Walk the header string, and parse each comma
+  // separated chunk as a separate header.
+  Vector<String> policy_items;
+  // policy_items = [ policy *( "," [ policy ] ) ]
+  policy.Split(',', policy_items);
+  for (const String& item : policy_items) {
+    Vector<String> entry_list;
+    // entry_list = [ entry *( ";" [ entry ] ) ]
+    item.Split(';', entry_list);
+    for (const String& entry : entry_list) {
+      // Split removes extra whitespaces by default
+      //     "name value1 value2" or "name".
+      Vector<String> tokens;
+      entry.Split(' ', tokens);
+      if (!feature_names.Contains(tokens[0])) {
         if (messages)
-          messages->push_back("Whitelist is not an array of strings.");
+          messages->push_back("Unrecognized feature: '" + tokens[0] + "'.");
         continue;
       }
 
+      WebFeaturePolicyFeature feature = feature_names.at(tokens[0]);
+      // If a policy has already been specified for the current feature, drop
+      // the new policy.
+      if (features_specified.QuickGet(static_cast<int>(feature)))
+        continue;
+
       WebParsedFeaturePolicyDeclaration whitelist;
       whitelist.feature = feature;
+      features_specified.QuickSet(static_cast<int>(feature));
       Vector<WebSecurityOrigin> origins;
-      String target_string;
-      for (size_t j = 0; j < targets->size(); ++j) {
-        if (targets->at(j)->AsString(&target_string)) {
-          if (EqualIgnoringASCIICase(target_string, "self")) {
-            if (!origin->IsUnique())
-              origins.push_back(origin);
-          } else if (target_string == "*") {
-            whitelist.matches_all_origins = true;
-          } else {
-            WebSecurityOrigin target_origin =
-                WebSecurityOrigin::CreateFromString(target_string);
-            if (!target_origin.IsNull() && !target_origin.IsUnique())
-              origins.push_back(target_origin);
-          }
+      // If a policy entry has no (optional) values, only valid syntax for allow
+      // attribute (e,g, allow="feature_name1; feature_name2 value"), enable the
+      // feature for src origin.
+      if (tokens.size() == 1) {
+        DCHECK(src_origin);
+        origins.push_back(src_origin);
+      }
+
+      for (size_t i = 1; i < tokens.size(); i++) {
+        if (EqualIgnoringASCIICase(tokens[i], "'self'")) {
+          origins.push_back(self_origin);
+        } else if (EqualIgnoringASCIICase(tokens[i], "'src'")) {
+          origins.push_back(src_origin);
+        } else if (EqualIgnoringASCIICase(tokens[i], "'none'")) {
+          continue;
+        } else if (tokens[i] == "*") {
+          whitelist.matches_all_origins = true;
+          break;
         } else {
-          if (messages)
-            messages->push_back("Whitelist is not an array of strings.");
+          WebSecurityOrigin target_origin =
+              WebSecurityOrigin::CreateFromString(tokens[i]);
+          if (!target_origin.IsNull() && !target_origin.IsUnique()) {
+            origins.push_back(target_origin);
+          } else if (messages) {
+            messages->push_back("Unrecognized origin: '" + tokens[i] + "'.");
+          }
         }
       }
       whitelist.origins = origins;
diff --git a/third_party/WebKit/Source/platform/feature_policy/FeaturePolicy.h b/third_party/WebKit/Source/platform/feature_policy/FeaturePolicy.h
index 392be02..d3358bd0 100644
--- a/third_party/WebKit/Source/platform/feature_policy/FeaturePolicy.h
+++ b/third_party/WebKit/Source/platform/feature_policy/FeaturePolicy.h
@@ -23,23 +23,39 @@
 typedef HashMap<String, WebFeaturePolicyFeature> FeatureNameMap;
 PLATFORM_EXPORT const FeatureNameMap& GetDefaultFeatureNameMap();
 
-// Converts a JSON feature policy string into a vector of whitelists, one for
-// each feature specified. Unrecognized features are filtered out. If |messages|
-// is not null, then any errors in the input will cause an error message to be
+// Converts a header policy string into a vector of whitelists, one for each
+// feature specified. Unrecognized features are filtered out. If |messages|
+// is not null, then any message in the input will cause a warning message to be
 // appended to it.
+// Example of a feature policy string:
+//     "vibrate a.com b.com; fullscreen 'none'; payment 'self', payment *".
 PLATFORM_EXPORT WebParsedFeaturePolicy
-ParseFeaturePolicy(const String& policy,
-                   RefPtr<SecurityOrigin>,
-                   Vector<String>* messages);
+ParseFeaturePolicyHeader(const String& policy,
+                         RefPtr<SecurityOrigin>,
+                         Vector<String>* messages);
 
-// Converts a JSON feature policy string into a vector of whitelists (see
-// comments above), with an explicit FeatureNameMap. This method is primarily
-// used for testing.
-PLATFORM_EXPORT WebParsedFeaturePolicy
-ParseFeaturePolicy(const String& policy,
-                   RefPtr<SecurityOrigin>,
-                   Vector<String>* messages,
-                   const FeatureNameMap& feature_names);
+// Converts a container policy string into a vector of whitelists, given self
+// and src origins provided, one for each feature specified. Unrecognized
+// features are filtered out. If |messages| is not null, then any message in the
+// input will cause as warning message to be appended to it.
+// Example of a feature policy string:
+//     "vibrate a.com 'src'; fullscreen 'none'; payment 'self', payment *".
+PLATFORM_EXPORT Vector<WebParsedFeaturePolicyDeclaration>
+ParseFeaturePolicyAttribute(const String& policy,
+                            RefPtr<SecurityOrigin> self_origin,
+                            RefPtr<SecurityOrigin> src_origin,
+                            Vector<String>* messages);
+
+// Converts a feature policy string into a vector of whitelists (see comments
+// above), with an explicit FeatureNameMap. This algorithm is called by both
+// header policy parsing and container policy parsing. |self_origin| and
+// |src_origin| are both nullable.
+PLATFORM_EXPORT Vector<WebParsedFeaturePolicyDeclaration> ParseFeaturePolicy(
+    const String& policy,
+    RefPtr<SecurityOrigin> self_origin,
+    RefPtr<SecurityOrigin> src_origin,
+    Vector<String>* messages,
+    const FeatureNameMap& feature_names);
 
 // Verifies whether feature policy is enabled and |feature| is supported in
 // feature policy.
diff --git a/third_party/WebKit/Source/platform/feature_policy/FeaturePolicyFuzzer.cpp b/third_party/WebKit/Source/platform/feature_policy/FeaturePolicyFuzzer.cpp
index a53f973..6661e361 100644
--- a/third_party/WebKit/Source/platform/feature_policy/FeaturePolicyFuzzer.cpp
+++ b/third_party/WebKit/Source/platform/feature_policy/FeaturePolicyFuzzer.cpp
@@ -20,6 +20,7 @@
   // TODO(csharrison): Be smarter about parsing this origin for performance.
   RefPtr<blink::SecurityOrigin> origin =
       blink::SecurityOrigin::CreateFromString("https://example.com/");
-  blink::ParseFeaturePolicy(WTF::String(data, size), origin.Get(), &messages);
+  blink::ParseFeaturePolicyHeader(WTF::String(data, size), origin.Get(),
+                                  &messages);
   return 0;
 }
diff --git a/third_party/WebKit/Source/platform/feature_policy/FeaturePolicyTest.cpp b/third_party/WebKit/Source/platform/feature_policy/FeaturePolicyTest.cpp
index b71ebca2..785d8caa 100644
--- a/third_party/WebKit/Source/platform/feature_policy/FeaturePolicyTest.cpp
+++ b/third_party/WebKit/Source/platform/feature_policy/FeaturePolicyTest.cpp
@@ -17,22 +17,31 @@
 namespace {
 
 const char* const kValidPolicies[] = {
-    "{\"vibrate\": []}",
-    "{\"vibrate\": [\"self\"]}",
-    "{\"vibrate\": [\"*\"]}",
-    "{\"vibrate\": [\"" ORIGIN_A "\"]}",
-    "{\"vibrate\": [\"" ORIGIN_B "\"]}",
-    "{\"vibrate\": [\"" ORIGIN_A "\", \"" ORIGIN_B "\"]}",
-    "{\"fullscreen\": [\"" ORIGIN_A "\"], \"payment\": [\"self\"]}",
-    "{\"fullscreen\": [\"" ORIGIN_A "\"]}, {\"payment\": [\"self\"]}"};
+    ";;",  // Empty policies.
+    "vibrate 'none'",
+    "vibrate 'self'",
+    "vibrate 'src'",  // Only valid for iframe allow attribute.
+    "vibrate",        // Only valid for iframe allow attribute.
+    "vibrate *",
+    "vibrate " ORIGIN_A "",
+    "vibrate " ORIGIN_B "",
+    "vibrate  " ORIGIN_A " " ORIGIN_B "",
+    "vibrate 'none' " ORIGIN_A " " ORIGIN_B "",
+    "vibrate " ORIGIN_A " 'none' " ORIGIN_B "",
+    "vibrate 'none' 'none' 'none'",
+    "vibrate " ORIGIN_A " *",
+    "fullscreen  " ORIGIN_A "; payment 'self'",
+    "fullscreen " ORIGIN_A "; payment *, vibrate 'self'"};
 
 const char* const kInvalidPolicies[] = {
-    "Not A JSON literal",
-    "\"Not a JSON object\"",
-    "[\"Also\", \"Not a JSON object\"]",
+    "badfeaturename",
+    "badfeaturename 'self'",
     "1.0",
-    "{\"vibrate\": \"Not a JSON array\"}",
-    "{\"vibrate\": [\"*\"], \"payment\": \"Not a JSON array\"}"};
+    "vibrate data://badorigin",
+    "vibrate https://bad;origin",
+    "vibrate https:/bad,origin",
+    "vibrate https://example.com, https://a.com",
+    "vibrate *, payment data://badorigin"};
 
 }  // namespace
 
@@ -57,8 +66,8 @@
   Vector<String> messages;
   for (const char* policy_string : kValidPolicies) {
     messages.clear();
-    ParseFeaturePolicy(policy_string, origin_a_.Get(), &messages,
-                       test_feature_name_map);
+    ParseFeaturePolicy(policy_string, origin_a_.Get(), origin_b_.Get(),
+                       &messages, test_feature_name_map);
     EXPECT_EQ(0UL, messages.size());
   }
 }
@@ -67,8 +76,8 @@
   Vector<String> messages;
   for (const char* policy_string : kInvalidPolicies) {
     messages.clear();
-    ParseFeaturePolicy(policy_string, origin_a_.Get(), &messages,
-                       test_feature_name_map);
+    ParseFeaturePolicy(policy_string, origin_a_.Get(), origin_b_.Get(),
+                       &messages, test_feature_name_map);
     EXPECT_NE(0UL, messages.size());
   }
 }
@@ -78,12 +87,12 @@
 
   // Empty policy.
   WebParsedFeaturePolicy parsed_policy = ParseFeaturePolicy(
-      "{}", origin_a_.Get(), &messages, test_feature_name_map);
+      "", origin_a_.Get(), origin_b_.Get(), &messages, test_feature_name_map);
   EXPECT_EQ(0UL, parsed_policy.size());
 
-  // Simple policy with "self".
+  // Simple policy with 'self'.
   parsed_policy =
-      ParseFeaturePolicy("{\"vibrate\": [\"self\"]}", origin_a_.Get(),
+      ParseFeaturePolicy("vibrate 'self'", origin_a_.Get(), origin_b_.Get(),
                          &messages, test_feature_name_map);
   EXPECT_EQ(1UL, parsed_policy.size());
 
@@ -93,8 +102,9 @@
   EXPECT_TRUE(origin_a_->IsSameSchemeHostPortAndSuborigin(
       parsed_policy[0].origins[0].Get()));
   // Simple policy with *.
-  parsed_policy = ParseFeaturePolicy("{\"vibrate\": [\"*\"]}", origin_a_.Get(),
-                                     &messages, test_feature_name_map);
+  parsed_policy =
+      ParseFeaturePolicy("vibrate *", origin_a_.Get(), origin_b_.Get(),
+                         &messages, test_feature_name_map);
   EXPECT_EQ(1UL, parsed_policy.size());
   EXPECT_EQ(WebFeaturePolicyFeature::kVibrate, parsed_policy[0].feature);
   EXPECT_TRUE(parsed_policy[0].matches_all_origins);
@@ -102,10 +112,10 @@
 
   // Complicated policy.
   parsed_policy = ParseFeaturePolicy(
-      "{\"vibrate\": [\"*\"], "
-      "\"fullscreen\": [\"https://example.net\", \"https://example.org\"], "
-      "\"payment\": [\"self\"]}",
-      origin_a_.Get(), &messages, test_feature_name_map);
+      "vibrate *; "
+      "fullscreen https://example.net https://example.org; "
+      "payment 'self'",
+      origin_a_.Get(), origin_b_.Get(), &messages, test_feature_name_map);
   EXPECT_EQ(3UL, parsed_policy.size());
   EXPECT_EQ(WebFeaturePolicyFeature::kVibrate, parsed_policy[0].feature);
   EXPECT_TRUE(parsed_policy[0].matches_all_origins);
@@ -122,6 +132,54 @@
   EXPECT_EQ(1UL, parsed_policy[2].origins.size());
   EXPECT_TRUE(origin_a_->IsSameSchemeHostPortAndSuborigin(
       parsed_policy[2].origins[0].Get()));
+
+  // Multiple policies.
+  parsed_policy = ParseFeaturePolicy(
+      "vibrate * https://example.net; "
+      "fullscreen https://example.net none https://example.org,"
+      "payment 'self' badorigin",
+      origin_a_.Get(), origin_b_.Get(), &messages, test_feature_name_map);
+  EXPECT_EQ(3UL, parsed_policy.size());
+  EXPECT_EQ(WebFeaturePolicyFeature::kVibrate, parsed_policy[0].feature);
+  EXPECT_TRUE(parsed_policy[0].matches_all_origins);
+  EXPECT_EQ(0UL, parsed_policy[0].origins.size());
+  EXPECT_EQ(WebFeaturePolicyFeature::kFullscreen, parsed_policy[1].feature);
+  EXPECT_FALSE(parsed_policy[1].matches_all_origins);
+  EXPECT_EQ(2UL, parsed_policy[1].origins.size());
+  EXPECT_TRUE(origin_b_->IsSameSchemeHostPortAndSuborigin(
+      parsed_policy[1].origins[0].Get()));
+  EXPECT_TRUE(origin_c_->IsSameSchemeHostPortAndSuborigin(
+      parsed_policy[1].origins[1].Get()));
+  EXPECT_EQ(WebFeaturePolicyFeature::kPayment, parsed_policy[2].feature);
+  EXPECT_FALSE(parsed_policy[2].matches_all_origins);
+  EXPECT_EQ(1UL, parsed_policy[2].origins.size());
+  EXPECT_TRUE(origin_a_->IsSameSchemeHostPortAndSuborigin(
+      parsed_policy[2].origins[0].Get()));
+
+  // Old (to be deprecated) iframe allow syntax.
+  messages.clear();
+  parsed_policy =
+      ParseFeaturePolicy("vibrate badname fullscreen payment", nullptr,
+                         origin_a_.Get(), &messages, test_feature_name_map);
+  // Expect 2 messages: one about deprecation warning, one about unrecognized
+  // feature name.
+  EXPECT_EQ(2UL, messages.size());
+  EXPECT_EQ(3UL, parsed_policy.size());
+  EXPECT_EQ(WebFeaturePolicyFeature::kVibrate, parsed_policy[0].feature);
+  EXPECT_FALSE(parsed_policy[0].matches_all_origins);
+  EXPECT_EQ(1UL, parsed_policy[0].origins.size());
+  EXPECT_TRUE(origin_a_->IsSameSchemeHostPortAndSuborigin(
+      parsed_policy[0].origins[0].Get()));
+  EXPECT_EQ(WebFeaturePolicyFeature::kFullscreen, parsed_policy[1].feature);
+  EXPECT_FALSE(parsed_policy[1].matches_all_origins);
+  EXPECT_EQ(1UL, parsed_policy[1].origins.size());
+  EXPECT_TRUE(origin_a_->IsSameSchemeHostPortAndSuborigin(
+      parsed_policy[1].origins[0].Get()));
+  EXPECT_EQ(WebFeaturePolicyFeature::kPayment, parsed_policy[2].feature);
+  EXPECT_FALSE(parsed_policy[2].matches_all_origins);
+  EXPECT_EQ(1UL, parsed_policy[2].origins.size());
+  EXPECT_TRUE(origin_a_->IsSameSchemeHostPortAndSuborigin(
+      parsed_policy[2].origins[0].Get()));
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/fonts/FontCustomPlatformData.cpp b/third_party/WebKit/Source/platform/fonts/FontCustomPlatformData.cpp
index 0760d36..0f336aa 100644
--- a/third_party/WebKit/Source/platform/fonts/FontCustomPlatformData.cpp
+++ b/third_party/WebKit/Source/platform/fonts/FontCustomPlatformData.cpp
@@ -33,6 +33,7 @@
 #include "platform/fonts/FontCustomPlatformData.h"
 
 #include "build/build_config.h"
+#include "platform/Histogram.h"
 #include "platform/LayoutTestSupport.h"
 #include "platform/SharedBuffer.h"
 #include "platform/fonts/FontCache.h"
@@ -124,14 +125,18 @@
         SkFontMgr::FontParameters().setAxes(axes.data(), axes.size())));
 
     if (sk_variation_font) {
+      ReportWebFontInstantiationResult(kSuccessVariableWebFont);
       return_typeface = sk_variation_font;
     } else {
+      ReportWebFontInstantiationResult(kErrorInstantiatingVariableFont);
       SkString family_name;
       base_typeface_->getFamilyName(&family_name);
       // TODO: Surface this as a console message?
       LOG(ERROR) << "Unable for apply variation axis properties for font: "
                  << family_name.c_str();
     }
+  } else {
+    ReportWebFontInstantiationResult(kSuccessConventionalWebFont);
   }
 
   return FontPlatformData(return_typeface, "", size,
@@ -153,6 +158,14 @@
       new FontCustomPlatformData(std::move(typeface), decoder.DecodedSize()));
 }
 
+void FontCustomPlatformData::ReportWebFontInstantiationResult(
+    WebFontInstantiationResult result) {
+  DEFINE_THREAD_SAFE_STATIC_LOCAL(
+      EnumerationHistogram, web_font_variable_fonts_ratio,
+      ("Blink.Fonts.VariableFontsRatio", kMaxWebFontInstantiationResult));
+  web_font_variable_fonts_ratio.Count(result);
+}
+
 bool FontCustomPlatformData::SupportsFormat(const String& format) {
   return DeprecatedEqualIgnoringCase(format, "truetype") ||
          DeprecatedEqualIgnoringCase(format, "opentype") ||
diff --git a/third_party/WebKit/Source/platform/fonts/FontCustomPlatformData.h b/third_party/WebKit/Source/platform/fonts/FontCustomPlatformData.h
index 8d3764d..034508d 100644
--- a/third_party/WebKit/Source/platform/fonts/FontCustomPlatformData.h
+++ b/third_party/WebKit/Source/platform/fonts/FontCustomPlatformData.h
@@ -73,6 +73,16 @@
   static bool SupportsFormat(const String&);
 
  private:
+  // These values are written to logs.  New enum values can be added, but
+  // existing enums must never be renumbered or deleted and reused.
+  enum WebFontInstantiationResult {
+    kErrorInstantiatingVariableFont = 0,
+    kSuccessConventionalWebFont = 1,
+    kSuccessVariableWebFont = 2,
+    kMaxWebFontInstantiationResult = 3
+  };
+
+  static void ReportWebFontInstantiationResult(WebFontInstantiationResult);
   FontCustomPlatformData(sk_sp<SkTypeface>, size_t data_size);
   sk_sp<SkTypeface> base_typeface_;
   size_t data_size_;
diff --git a/third_party/WebKit/Source/platform/fonts/fuchsia/FontPlatformDataFuchsia.cpp b/third_party/WebKit/Source/platform/fonts/fuchsia/FontPlatformDataFuchsia.cpp
index 9f9db2e..040e4c5 100644
--- a/third_party/WebKit/Source/platform/fonts/fuchsia/FontPlatformDataFuchsia.cpp
+++ b/third_party/WebKit/Source/platform/fonts/fuchsia/FontPlatformDataFuchsia.cpp
@@ -35,8 +35,7 @@
 void FontPlatformData::SetupPaint(SkPaint* paint,
                                   float device_scale_factor,
                                   const Font*) const {
-  // TODO(fuchsia): Implement this when UI support is ready. crbug.com/750946
-  NOTIMPLEMENTED();
+  paint->setTypeface(typeface_);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp
index 2f3a7a6..de8443f 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp
@@ -597,21 +597,76 @@
   return ts.Release();
 }
 
+class GraphicsLayer::LayersAsJSONArray {
+ public:
+  LayersAsJSONArray(LayerTreeFlags flags)
+      : flags_(flags),
+        next_transform_id_(1),
+        layers_json_(JSONArray::Create()),
+        transforms_json_(JSONArray::Create()) {}
+
+  // Outputs the layer tree rooted at |layer| as a JSON array, in paint order,
+  // and the transform tree also as a JSON array.
+  std::unique_ptr<JSONObject> operator()(const GraphicsLayer& layer) {
+    auto json = JSONObject::Create();
+    Walk(layer, 0, FloatPoint());
+    json->SetArray("layers", std::move(layers_json_));
+    if (transforms_json_->size())
+      json->SetArray("transforms", std::move(transforms_json_));
+    return json;
+  }
+
+  void Walk(const GraphicsLayer& layer,
+            int parent_transform_id,
+            const FloatPoint& parent_offset) {
+    FloatPoint offset = parent_offset;
+    int transform_id = parent_transform_id;
+    std::unique_ptr<JSONObject> transform_json;
+    if (!layer.transform_.IsIdentity() || layer.rendering_context3d_) {
+      transform_json = JSONObject::Create();
+      transform_id = next_transform_id_++;
+      transform_json->SetInteger("id", transform_id);
+      if (parent_transform_id)
+        transform_json->SetInteger("parent", parent_transform_id);
+      layer.AddTransformJSONProperties(*transform_json, rendering_context_map_);
+      transforms_json_->PushObject(std::move(transform_json));
+
+      offset = FloatPoint();
+    }
+
+    auto json =
+        layer.LayerAsJSONInternal(flags_, rendering_context_map_, offset);
+    if (transform_id)
+      json->SetInteger("transform", transform_id);
+    layers_json_->PushObject(std::move(json));
+
+    offset += layer.position_;
+    for (auto& child : layer.children_)
+      Walk(*child, transform_id, offset);
+  }
+
+ private:
+  LayerTreeFlags flags_;
+  int next_transform_id_;
+  RenderingContextMap rendering_context_map_;
+  std::unique_ptr<JSONArray> layers_json_;
+  std::unique_ptr<JSONArray> transforms_json_;
+};
+
 std::unique_ptr<JSONObject> GraphicsLayer::LayerTreeAsJSON(
     LayerTreeFlags flags) const {
-  RenderingContextMap rendering_context_map;
-  if (flags & kOutputAsLayerTree)
+  if (flags & kOutputAsLayerTree) {
+    RenderingContextMap rendering_context_map;
     return LayerTreeAsJSONInternal(flags, rendering_context_map);
-  std::unique_ptr<JSONObject> json = JSONObject::Create();
-  std::unique_ptr<JSONArray> layers_array = JSONArray::Create();
-  LayersAsJSONArray(flags, rendering_context_map, layers_array.get());
-  json->SetArray("layers", std::move(layers_array));
-  return json;
+  }
+
+  return LayersAsJSONArray(flags)(*this);
 }
 
 std::unique_ptr<JSONObject> GraphicsLayer::LayerAsJSONInternal(
     LayerTreeFlags flags,
-    RenderingContextMap& rendering_context_map) const {
+    RenderingContextMap& rendering_context_map,
+    const FloatPoint& offset) const {
   std::unique_ptr<JSONObject> json = JSONObject::Create();
 
   if (flags & kLayerTreeIncludesDebugInfo)
@@ -619,8 +674,9 @@
 
   json->SetString("name", DebugName());
 
-  if (position_ != FloatPoint())
-    json->SetArray("position", PointAsJSONArray(position_));
+  FloatPoint position = offset + position_;
+  if (position != FloatPoint())
+    json->SetArray("position", PointAsJSONArray(position));
 
   if (flags & kLayerTreeIncludesDebugInfo &&
       offset_from_layout_object_ != DoubleSize()) {
@@ -628,11 +684,6 @@
                    SizeAsJSONArray(offset_from_layout_object_));
   }
 
-  if (has_transform_origin_ &&
-      transform_origin_ !=
-          FloatPoint3D(size_.Width() * 0.5f, size_.Height() * 0.5f, 0))
-    json->SetArray("transformOrigin", PointAsJSONArray(transform_origin_));
-
   if (size_ != IntSize())
     json->SetArray("bounds", SizeAsJSONArray(size_));
 
@@ -650,21 +701,6 @@
   if (contents_opaque_)
     json->SetBoolean("contentsOpaque", contents_opaque_);
 
-  if (!should_flatten_transform_)
-    json->SetBoolean("shouldFlattenTransform", should_flatten_transform_);
-
-  if (rendering_context3d_) {
-    RenderingContextMap::const_iterator it =
-        rendering_context_map.find(rendering_context3d_);
-    int context_id = rendering_context_map.size() + 1;
-    if (it == rendering_context_map.end())
-      rendering_context_map.Set(rendering_context3d_, context_id);
-    else
-      context_id = it->value;
-
-    json->SetInteger("3dRenderingContext", context_id);
-  }
-
   if (draws_content_)
     json->SetBoolean("drawsContent", draws_content_);
 
@@ -684,8 +720,8 @@
                     background_color_.NameForLayoutTreeAsText());
   }
 
-  if (!transform_.IsIdentity())
-    json->SetArray("transform", TransformAsJSONArray(transform_));
+  if (flags & kOutputAsLayerTree)
+    AddTransformJSONProperties(*json, rendering_context_map);
 
   if (flags & kLayerTreeIncludesPaintInvalidations)
     GetRasterInvalidationTrackingMap().AsJSON(this, json.get());
@@ -785,15 +821,27 @@
   return json;
 }
 
-void GraphicsLayer::LayersAsJSONArray(
-    LayerTreeFlags flags,
-    RenderingContextMap& rendering_context_map,
-    JSONArray* json_array) const {
-  json_array->PushObject(LayerAsJSONInternal(flags, rendering_context_map));
+void GraphicsLayer::AddTransformJSONProperties(
+    JSONObject& json,
+    RenderingContextMap& rendering_context_map) const {
+  if (!transform_.IsIdentity())
+    json.SetArray("transform", TransformAsJSONArray(transform_));
 
-  if (children_.size()) {
-    for (auto& child : children_)
-      child->LayersAsJSONArray(flags, rendering_context_map, json_array);
+  if (!transform_.IsIdentityOrTranslation())
+    json.SetArray("origin", PointAsJSONArray(transform_origin_));
+
+  if (!should_flatten_transform_)
+    json.SetBoolean("flattenInheritedTransform", false);
+
+  if (rendering_context3d_) {
+    auto it = rendering_context_map.find(rendering_context3d_);
+    int context_id = rendering_context_map.size() + 1;
+    if (it == rendering_context_map.end())
+      rendering_context_map.Set(rendering_context3d_, context_id);
+    else
+      context_id = it->value;
+
+    json.SetInteger("renderingContext", context_id);
   }
 }
 
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.h b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.h
index 0befa1df..c3cb411 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.h
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.h
@@ -327,12 +327,12 @@
   std::unique_ptr<JSONObject> LayerTreeAsJSONInternal(
       LayerTreeFlags,
       RenderingContextMap&) const;
-  // Outputs the layer tree rooted at |this| as a JSON array, in paint order.
-  void LayersAsJSONArray(LayerTreeFlags,
-                         RenderingContextMap&,
-                         JSONArray*) const;
-  std::unique_ptr<JSONObject> LayerAsJSONInternal(LayerTreeFlags,
-                                                  RenderingContextMap&) const;
+  std::unique_ptr<JSONObject> LayerAsJSONInternal(
+      LayerTreeFlags,
+      RenderingContextMap&,
+      const FloatPoint& = FloatPoint()) const;
+  void AddTransformJSONProperties(JSONObject&, RenderingContextMap&) const;
+  class LayersAsJSONArray;
 
   sk_sp<PaintRecord> CaptureRecord();
 
diff --git a/third_party/WebKit/Source/platform/wtf/typed_arrays/ArrayBufferContents.cpp b/third_party/WebKit/Source/platform/wtf/typed_arrays/ArrayBufferContents.cpp
index 900324a..30cf7c9 100644
--- a/third_party/WebKit/Source/platform/wtf/typed_arrays/ArrayBufferContents.cpp
+++ b/third_party/WebKit/Source/platform/wtf/typed_arrays/ArrayBufferContents.cpp
@@ -138,7 +138,16 @@
   // Linux by default has a small address space limit, which we chew up pretty
   // quickly with large memory reservations. To mitigate this, we bump up the
   // limit for array buffer reservations. See https://crbug.com/750378
-  CHECK(sandbox::ResourceLimits::AdjustCurrent(RLIMIT_AS, size));
+  //
+  // In general, returning nullptr is dangerous, as unsuspecting code may do an
+  // offset-from-null and end up with an accessible but incorrect address.  This
+  // function (ReserveMemory) is only used in contexts that expect allocation
+  // may fail and explicitly handle the nullptr return case. This code is also
+  // only used on 64-bit to create guard regions, which provides further
+  // protection.
+  if (!sandbox::ResourceLimits::AdjustCurrent(RLIMIT_AS, size)) {
+    return nullptr;
+  }
 #endif
 
   // TODO(crbug.com/735209): On Windows this commits all the memory, rather than
diff --git a/third_party/WebKit/public/platform/WebFeaturePolicyFeature.h b/third_party/WebKit/public/platform/WebFeaturePolicyFeature.h
index 9e4e5f3c..2c271ba5 100644
--- a/third_party/WebKit/public/platform/WebFeaturePolicyFeature.h
+++ b/third_party/WebKit/public/platform/WebFeaturePolicyFeature.h
@@ -45,7 +45,9 @@
   kSyncXHR,
   // Controls access to the WebUSB API.
   kUsb,
-  LAST_FEATURE = kUsb
+  // Controls access to AOM event listeners.
+  kAccessibilityEvents,
+  LAST_FEATURE = kAccessibilityEvents
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/public/platform/modules/permissions/permission.mojom b/third_party/WebKit/public/platform/modules/permissions/permission.mojom
index 7f23845..37dc9ea 100644
--- a/third_party/WebKit/public/platform/modules/permissions/permission.mojom
+++ b/third_party/WebKit/public/platform/modules/permissions/permission.mojom
@@ -18,6 +18,7 @@
   VIDEO_CAPTURE,
   BACKGROUND_SYNC,
   SENSORS,
+  ACCESSIBILITY_EVENTS,
 };
 
 struct MidiPermissionDescriptor {
diff --git a/third_party/android_support_test_runner/rules_java.info b/third_party/android_support_test_runner/rules_java.info
new file mode 100644
index 0000000..28c8330
--- /dev/null
+++ b/third_party/android_support_test_runner/rules_java.info
@@ -0,0 +1,13 @@
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+aidl = [  ]
+assets = [  ]
+has_classes_jar = true
+has_native_libraries = false
+has_proguard_flags = false
+has_r_text_file = true
+is_manifest_empty = true
+resources = [ "res/values/values.xml" ]
+subjar_tuples = [  ]
+subjars = [  ]
diff --git a/third_party/gvr-android-sdk/BUILD.gn b/third_party/gvr-android-sdk/BUILD.gn
index c04ac54..3fa19e67 100644
--- a/third_party/gvr-android-sdk/BUILD.gn
+++ b/third_party/gvr-android-sdk/BUILD.gn
@@ -13,7 +13,7 @@
 }
 
 android_aar_prebuilt("gvr_common_java") {
-  aar_path = "common_library.aar"
+  aar_path = "src/libraries/sdk-common-1.80.0.aar"
   proguard_configs = [ "proguard-gvr-chromium.txt" ]
   ignore_native_libraries = true
 
@@ -39,6 +39,7 @@
     "*google/common/logging/nano/Vr\$VREvent\$DoublePrecisionTransform.class",
     "*google/common/logging/nano/Vr\$VREvent\$Cyclops*.class",
     "*google/common/logging/nano/Vr\$VREvent\$AudioStats.class",
+    "*ThrowableExtension*.class",
   ]
 
   deps = [
@@ -47,7 +48,7 @@
 }
 
 android_aar_prebuilt("gvr_controller_java") {
-  aar_path = "src/libraries/sdk-controller-1.60.1.aar"
+  aar_path = "src/libraries/sdk-controller-1.80.0.aar"
 }
 
 config("libgvr_config") {
diff --git a/third_party/gvr-android-sdk/README.chromium b/third_party/gvr-android-sdk/README.chromium
index 47a8431..12aa13c 100644
--- a/third_party/gvr-android-sdk/README.chromium
+++ b/third_party/gvr-android-sdk/README.chromium
@@ -1,9 +1,9 @@
 Name: Google VR SDK
 Short Name: gvr
 URL: https://github.com/googlevr/gvr-android-sdk
-Version: 1.60.1
-Date: 06 June 2017
-Revision: a27f768b13682189c23eed69656319db5ef7cbfc
+Version: 1.80.0
+Date: 29 August 2017
+Revision: ee5cb1c6138d0be57e82ddafc1b54d7d3e3e5560
 License: Apache 2.0
 License File: LICENSE
 Security Critical: yes
@@ -14,13 +14,9 @@
 complex API for supporting Daydream-ready phones and the Daydream controller.
 
 Local Modifications:
-Only header files in NDK are used. Due to binary size concern, we have decided
-to use a static shim library instead of the shared library that comes with
-this checkout. The static libraries are downloaded from a public storage through
-gclient sync. Currently, the static libraries needs a newer version of
-common_library.aar than the one provided by this checkout. So we also download
-it from the same public storage. Once the version on github catches up, we will
-remove common_library.aar.
+Due to binary size concern, we have decided to use a static shim library instead
+of the shared library that comes with this checkout. The static libraries are
+downloaded from a public storage through gclient sync.
 For Version 1.10.0, we have two date: 6 Dec 2016 and 10 Feb 2017. The latter
 version cherrypick a CL that fix a crash on K and L.
 All JNI calls in the static library also needs to be manually registered. So
diff --git a/third_party/gvr-android-sdk/common_library.aar.sha1 b/third_party/gvr-android-sdk/common_library.aar.sha1
deleted file mode 100644
index ca06c1af..0000000
--- a/third_party/gvr-android-sdk/common_library.aar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-2e65f66d39019f6c9be93c6cb28e2d434667daa5
\ No newline at end of file
diff --git a/third_party/gvr-android-sdk/controller_test_api_java.info b/third_party/gvr-android-sdk/controller_test_api_java.info
new file mode 100644
index 0000000..a2ebd4a8
--- /dev/null
+++ b/third_party/gvr-android-sdk/controller_test_api_java.info
@@ -0,0 +1,13 @@
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+aidl = [  ]
+assets = [  ]
+has_classes_jar = true
+has_native_libraries = false
+has_proguard_flags = false
+has_r_text_file = false
+is_manifest_empty = true
+resources = [  ]
+subjar_tuples = [  ]
+subjars = [  ]
diff --git a/third_party/gvr-android-sdk/gvr_api_jni.h b/third_party/gvr-android-sdk/gvr_api_jni.h
index a8c1115..26e19ec1d 100644
--- a/third_party/gvr-android-sdk/gvr_api_jni.h
+++ b/third_party/gvr-android-sdk/gvr_api_jni.h
@@ -522,7 +522,15 @@
     JNIEnv* env,
     jobject jcaller,
     jlong nativeGvrContext,
-    jfloatArray outPose,
+    jfloatArray outRotation,
+    jlong timeNs);
+
+JNI_GENERATOR_EXPORT void
+Java_com_google_vr_ndk_base_GvrApi_nativeGetHeadSpaceFromStartSpaceTransform(
+    JNIEnv* env,
+    jobject jcaller,
+    jlong nativeGvrContext,
+    jfloatArray outTransform,
     jlong timeNs);
 
 JNI_GENERATOR_EXPORT void
@@ -679,7 +687,8 @@
                                                        jobject jcaller,
                                                        jlong nativeGvrContext,
                                                        jfloat x,
-                                                       jfloat y);
+                                                       jfloat y,
+                                                       jfloat rotation);
 
 JNI_GENERATOR_EXPORT void
 Java_com_google_vr_ndk_base_GvrApi_nativeDumpDebugData(JNIEnv* env,
@@ -1266,6 +1275,15 @@
      "V",
      reinterpret_cast<void*>(
          Java_com_google_vr_ndk_base_GvrApi_nativeGetHeadSpaceFromStartSpaceRotation)},
+    {"nativeGetHeadSpaceFromStartSpaceTransform",
+     "("
+     "J"
+     "[F"
+     "J"
+     ")"
+     "V",
+     reinterpret_cast<void*>(
+         Java_com_google_vr_ndk_base_GvrApi_nativeGetHeadSpaceFromStartSpaceTransform)},
     {"nativeSetIgnoreManualPauseResumeTracker",
      "("
      "J"
@@ -1449,6 +1467,7 @@
      "J"
      "F"
      "F"
+     "F"
      ")"
      "V",
      reinterpret_cast<void*>(
diff --git a/third_party/gvr-android-sdk/gvr_common_java.info b/third_party/gvr-android-sdk/gvr_common_java.info
new file mode 100644
index 0000000..aacf1d9
--- /dev/null
+++ b/third_party/gvr-android-sdk/gvr_common_java.info
@@ -0,0 +1,13 @@
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+aidl = [  ]
+assets = [  ]
+has_classes_jar = true
+has_native_libraries = false
+has_proguard_flags = false
+has_r_text_file = true
+is_manifest_empty = true
+resources = [ "res/drawable-hdpi-v4/quantum_ic_close_white_24.png", "res/drawable-hdpi-v4/quantum_ic_settings_white_24.png", "res/drawable-hdpi-v4/transition.png", "res/drawable-mdpi-v4/quantum_ic_close_white_24.png", "res/drawable-mdpi-v4/quantum_ic_settings_white_24.png", "res/drawable-mdpi-v4/transition.png", "res/drawable-v21/rippleable.xml", "res/drawable-xhdpi-v4/quantum_ic_close_white_24.png", "res/drawable-xhdpi-v4/quantum_ic_settings_white_24.png", "res/drawable-xxhdpi-v4/quantum_ic_close_white_24.png", "res/drawable-xxhdpi-v4/quantum_ic_settings_white_24.png", "res/drawable-xxxhdpi-v4/quantum_ic_close_white_24.png", "res/drawable-xxxhdpi-v4/quantum_ic_settings_white_24.png", "res/drawable/rippleable.xml", "res/layout-land/back_button.xml", "res/layout-land/settings_button.xml", "res/layout-land/ui_layer_with_portrait_support.xml", "res/layout-ldrtl-land-v17/back_button.xml", "res/layout-ldrtl-land-v17/settings_button.xml", "res/layout-ldrtl-v17/back_button.xml", "res/layout-ldrtl-v17/settings_button.xml", "res/layout/back_button.xml", "res/layout/settings_button.xml", "res/layout/transition_view.xml", "res/layout/ui_layer.xml", "res/layout/ui_layer_with_portrait_support.xml", "res/values-ar/values.xml", "res/values-bg/values.xml", "res/values-ca/values.xml", "res/values-cs/values.xml", "res/values-da/values.xml", "res/values-de/values.xml", "res/values-el/values.xml", "res/values-en-rGB/values.xml", "res/values-es-rUS/values.xml", "res/values-es/values.xml", "res/values-fa/values.xml", "res/values-fi/values.xml", "res/values-fr-rCA/values.xml", "res/values-fr/values.xml", "res/values-hi/values.xml", "res/values-hr/values.xml", "res/values-hu/values.xml", "res/values-id/values.xml", "res/values-it/values.xml", "res/values-iw/values.xml", "res/values-ja/values.xml", "res/values-ko/values.xml", "res/values-land/values.xml", "res/values-lt/values.xml", "res/values-lv/values.xml", "res/values-nl/values.xml", "res/values-no/values.xml", "res/values-pl/values.xml", "res/values-pt-rBR/values.xml", "res/values-pt-rPT/values.xml", "res/values-ro/values.xml", "res/values-ru/values.xml", "res/values-sk/values.xml", "res/values-sl/values.xml", "res/values-sr/values.xml", "res/values-sv/values.xml", "res/values-th/values.xml", "res/values-tl/values.xml", "res/values-tr/values.xml", "res/values-uk/values.xml", "res/values-v19/values.xml", "res/values-v21/values.xml", "res/values-vi/values.xml", "res/values-zh-rCN/values.xml", "res/values-zh-rTW/values.xml", "res/values/values.xml" ]
+subjar_tuples = [  ]
+subjars = [  ]
diff --git a/third_party/gvr-android-sdk/gvr_controller_java.info b/third_party/gvr-android-sdk/gvr_controller_java.info
new file mode 100644
index 0000000..a2ebd4a8
--- /dev/null
+++ b/third_party/gvr-android-sdk/gvr_controller_java.info
@@ -0,0 +1,13 @@
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+aidl = [  ]
+assets = [  ]
+has_classes_jar = true
+has_native_libraries = false
+has_proguard_flags = false
+has_r_text_file = false
+is_manifest_empty = true
+resources = [  ]
+subjar_tuples = [  ]
+subjars = [  ]
diff --git a/third_party/gvr-android-sdk/libgvr_shim_static_arm.a.sha1 b/third_party/gvr-android-sdk/libgvr_shim_static_arm.a.sha1
index c3106905..13265b62 100644
--- a/third_party/gvr-android-sdk/libgvr_shim_static_arm.a.sha1
+++ b/third_party/gvr-android-sdk/libgvr_shim_static_arm.a.sha1
@@ -1 +1 @@
-a951bb4b47a6a250c2705cec4a772b606d1b39ae
\ No newline at end of file
+9007b02cbd9dc0765e89e63d2ae4c66f8285832e
\ No newline at end of file
diff --git a/third_party/gvr-android-sdk/libgvr_shim_static_arm64.a.sha1 b/third_party/gvr-android-sdk/libgvr_shim_static_arm64.a.sha1
index 51e10c7..99d98986 100644
--- a/third_party/gvr-android-sdk/libgvr_shim_static_arm64.a.sha1
+++ b/third_party/gvr-android-sdk/libgvr_shim_static_arm64.a.sha1
@@ -1 +1 @@
-8536e70560ab4f3a3f4f93d9dd0fc639c898a4d7
\ No newline at end of file
+7bca9dfff2a90393812852ce3b0c7d4c15d37cec
\ No newline at end of file
diff --git a/third_party/leveldatabase/env_chromium.cc b/third_party/leveldatabase/env_chromium.cc
index a670d24..7d4a6ca 100644
--- a/third_party/leveldatabase/env_chromium.cc
+++ b/third_party/leveldatabase/env_chromium.cc
@@ -476,11 +476,10 @@
   char buf[512];
   base::snprintf(buf, sizeof(buf), "%s (ChromeMethodBFE: %d::%s::%d)",
            message.c_str(), method, MethodIDToString(method), -error);
-  if (error == base::File::FILE_ERROR_NOT_FOUND) {
-    return Status::NotFound(filename, buf);
-  } else {
-    return Status::IOError(filename, buf);
-  }
+  // TOOD(crbug.com/760362): Map base::File::FILE_ERROR_NOT_FOUND to
+  //                         Status::NotFound, after fixing LevelDB to handle
+  //                         the NotFound correctly.
+  return Status::IOError(filename, buf);
 }
 
 Status MakeIOError(Slice filename,
diff --git a/tools/accessibility/rebase_dump_accessibility_tree_test.py b/tools/accessibility/rebase_dump_accessibility_tree_test.py
index 2598332..80db0cc 100755
--- a/tools/accessibility/rebase_dump_accessibility_tree_test.py
+++ b/tools/accessibility/rebase_dump_accessibility_tree_test.py
@@ -34,6 +34,11 @@
 # The location of the DumpAccessibilityTree html test files and expectations.
 TEST_DATA_PATH = os.path.join(os.getcwd(), 'content/test/data/accessibility')
 
+# Colors for easier debugging.
+# TODO check environment  to determine whether terminal is rich or interactive.
+BRIGHT_COLOR = '\033[93m'
+NORMAL_COLOR = '\033[0m'
+
 # A global that keeps track of files we've already updated, so we don't
 # bother to update the same file twice.
 completed_files = set()
@@ -118,9 +123,10 @@
       platform = tokens[6]
       build = tokens[8]
       logdog_prefix = 'chromium/bb/%s/%s/%s' % (bucket, platform, build)
-      logdog_steps = '%s/+/recipes/steps' % logdog_prefix
-      print logdog_prefix
-      steps = os.popen('cit logdog ls "%s"' % logdog_steps).readlines()
+      logdog_steps = '%s/+/recipes/steps/*/*/*' % logdog_prefix
+      logdog_query = 'cit logdog query -results 999 -path "%s"' % logdog_steps
+      print (BRIGHT_COLOR + '=> %s' + NORMAL_COLOR) % logdog_query
+      steps = os.popen(logdog_query).readlines()
       a11y_step = None
       for step in steps:
         if (step.find('content_browsertests') >= 0 and
@@ -131,9 +137,8 @@
       if not a11y_step:
         print 'No content_browsertests (with patch) step found'
         continue
-      print a11y_step
-      logdog_cat = ('cit logdog cat -raw "%s/%s/0/stdout"' %
-        (logdog_steps, a11y_step))
+      logdog_cat = 'cit logdog cat -raw "chromium%s"' % a11y_step
+      print (BRIGHT_COLOR + '=> %s' + NORMAL_COLOR) % logdog_cat
       output = os.popen(logdog_cat).read()
       ParseLog(output)
 
diff --git a/tools/binary_size/README.md b/tools/binary_size/README.md
index a2486a44..cff9d1339 100644
--- a/tools/binary_size/README.md
+++ b/tools/binary_size/README.md
@@ -39,6 +39,9 @@
 # Diff BEFORE_REV and AFTER_REV using build artifacts downloaded from perf bots.
 tools/binary_size/diagnose_bloat.py AFTER_REV --reference-rev BEFORE_REV --cloud -v
 
+# Fetch a single .size and .apk from the bots:
+tools/binary_size/diagnose_bloat.py AFTER_REV --cloud --single
+
 # Build and diff all contiguous revs in range BEFORE_REV..AFTER_REV for src/v8.
 tools/binary_size/diagnose_bloat.py AFTER_REV --reference-rev BEFORE_REV --subrepo v8 --all -v
 
@@ -136,7 +139,7 @@
 *** note
 **Note:** Refer to
 [diagnose_bloat.py](https://cs.chromium.org/search/?q=file:diagnose_bloat.py+gn_args)
-for list of GN args to build a Release binary.
+for list of GN args to build a Release binary (or just use the tool with --single).
 ***
 
 Example Usage:
diff --git a/tools/binary_size/diagnose_bloat.py b/tools/binary_size/diagnose_bloat.py
index 8f475b3..a0df3977 100755
--- a/tools/binary_size/diagnose_bloat.py
+++ b/tools/binary_size/diagnose_bloat.py
@@ -429,6 +429,12 @@
         for s, before, after in stats:
           _PrintAndWriteToFile(f, '{:>+10} {} {} for range: {}..{}',
                                s.value, s.units, s.name, before, after)
+    elif self.build_archives:
+      supersize_path = os.path.join(_BINARY_SIZE_DIR, 'supersize')
+      size_path = os.path.join(self.build_archives[0].dir, self.build.size_name)
+      logging.info('Enter supersize console via: %s console %s',
+                   os.path.relpath(supersize_path), os.path.relpath(size_path))
+
 
   def _AddDiffSummaryStat(self, before, after):
     stat = None
@@ -572,7 +578,7 @@
   rev_seq = '%s^..%s' % (reference_rev, rev)
   stdout = _GitCmd(['rev-list', rev_seq], subrepo)
   all_revs = stdout.splitlines()[::-1]
-  if all_in_range:
+  if all_in_range or len(all_revs) < 2:
     revs = all_revs
   else:
     revs = [all_revs[0], all_revs[-1]]
@@ -590,8 +596,6 @@
     if retcode:
       _Die(message)
 
-  if rev == reference_rev:
-    _Die('rev and reference-rev cannot be equal')
   no_obj_message = ('%s either doesn\'t exist or your local repo is out of '
                     'date, try "git fetch origin master"')
   git_fatal(['cat-file', '-e', rev], no_obj_message % rev)
@@ -744,6 +748,9 @@
                       action='store_true',
                       help='Download build artifacts from perf builders '
                       '(Googlers only).')
+  parser.add_argument('--single',
+                      action='store_true',
+                      help='Sets --reference-rev=rev')
   parser.add_argument('--depot-tools-path',
                       help='Custom path to depot tools. Needed for --cloud if '
                            'depot tools isn\'t in your PATH.')
@@ -809,8 +816,10 @@
   if build.IsLinux():
     _VerifyUserAccepts('Linux diffs have known deficiencies (crbug/717550).')
 
-  rev, reference_rev = _ValidateRevs(
-      args.rev, args.reference_rev or args.rev + '^', subrepo)
+  reference_rev = args.reference_rev or args.rev + '^'
+  if args.single:
+    reference_rev = args.rev
+  rev, reference_rev = _ValidateRevs(args.rev, reference_rev, subrepo)
   revs = _GenerateRevList(rev, reference_rev, args.all, subrepo)
   with _TmpCopyBinarySizeDir() as supersize_path:
     diffs = [NativeDiff(build.size_name, supersize_path)]
diff --git a/tools/binary_size/libsupersize/archive.py b/tools/binary_size/libsupersize/archive.py
index 17bd6046..44f1e3a5 100644
--- a/tools/binary_size/libsupersize/archive.py
+++ b/tools/binary_size/libsupersize/archive.py
@@ -678,7 +678,9 @@
     if not os.path.exists(map_path):
       map_path += '.gz'
     if not os.path.exists(map_path):
-      parser.error('Could not find .map(.gz)? file. Use --map-file.')
+      parser.error('Could not find .map(.gz)? file. Ensure you have built with '
+                   'is_official_build=true, or use --map-file to point me a '
+                   'linker map file.')
 
   tool_prefix = lazy_paths.VerifyToolPrefix()
   output_directory = None
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 1f6aef2d..6e9e3ca 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -466,6 +466,13 @@
       'Windows Dev': 'debug_bot_minimal_symbols',
     },
 
+    # Manually triggered internal builders running on LUCI.
+    'luci.infra-internal.triggered': {
+      'gn-builder-linux': 'gn_linux_upload',
+      'gn-builder-mac': 'release_bot',
+      'gn-builder-win': 'release_bot_x86_minimal_symbols',
+    },
+
     'tryserver.blink': {
       # Most tryservers should have '_trybot' in their config names, but
       # 'release_trybot' includes 'dcheck_always_on', and the blink
diff --git a/tools/md_browser/md_browser.py b/tools/md_browser/md_browser.py
index e24e29f..16217107 100755
--- a/tools/md_browser/md_browser.py
+++ b/tools/md_browser/md_browser.py
@@ -145,7 +145,10 @@
     elif path.lower().endswith('.md'):
       self._DoMD(path)
     elif os.path.exists(full_path + '/README.md'):
-      self._DoMD(path + '/README.md')
+      separator = '/'
+      if path.endswith('/'):
+        separator = ''
+      self._DoMD(path + separator + 'README.md')
     elif path.lower().endswith('.png'):
       self._DoImage(full_path, 'image/png')
     elif path.lower().endswith('.jpg'):
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 10fb755c..bb9eeea5 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -1625,7 +1625,8 @@
 </action>
 
 <action name="AppCloseButton_Clk">
-  <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
+  <obsolete>Unused as of 08/2017</obsolete>
+  <owner>jamescook@chromium.org</owner>
   <description>Please enter the description of this user action.</description>
 </action>
 
@@ -11182,6 +11183,7 @@
 </action>
 
 <action name="MobileTabClobbered">
+  <obsolete>Deprecated as of 8/2017</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>
@@ -15646,6 +15648,15 @@
   </description>
 </action>
 
+<action name="Signin_ImpressionWithAccount_FromNTPContentSuggestions">
+  <owner>bsazonov@chromium.org</owner>
+  <description>
+    Recorded when starting sign-in using the promo view, with a default account,
+    from NTP content suggestions
+    (signin_metrics::AccessPoint::ACCESS_POINT_NTP_CONTENT_SUGGESTIONS).
+  </description>
+</action>
+
 <action name="Signin_ImpressionWithAccount_FromRecentTabs">
   <owner>jlebel@chromium.org</owner>
   <description>
@@ -15679,6 +15690,15 @@
   </description>
 </action>
 
+<action name="Signin_ImpressionWithNoAccount_FromNTPContentSuggestions">
+  <owner>bsazonov@chromium.org</owner>
+  <description>
+    Recorded when starting sign-in using the promo view, with no default
+    account, from NTP content suggestions
+    (signin_metrics::AccessPoint::ACCESS_POINT_NTP_CONTENT_SUGGESTIONS).
+  </description>
+</action>
+
 <action name="Signin_ImpressionWithNoAccount_FromRecentTabs">
   <owner>jlebel@chromium.org</owner>
   <description>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 3224108..eecc71d 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -6033,6 +6033,8 @@
   <int value="35" label="Media engagement setting"/>
   <int value="36" label="Sound setting"/>
   <int value="37" label="Client hints setting"/>
+  <int value="38" label="Sensors setting"/>
+  <int value="39" label="Accessibility events setting"/>
 </enum>
 
 <enum name="ContentTypeParseableResult">
@@ -12044,7 +12046,8 @@
   <int value="340" label="SCREENLOCK_PRIVATE_ON_CHANGED"/>
   <int value="341" label="SCREENLOCK_PRIVATE_ON_AUTH_ATTEMPTED"/>
   <int value="342" label="TYPES_CHROME_SETTING_ON_CHANGE"/>
-  <int value="343" label="TYPES_PRIVATE_CHROME_DIRECT_SETTING_ON_CHANGE"/>
+  <int value="343"
+      label="DELETED_TYPES_PRIVATE_CHROME_DIRECT_SETTING_ON_CHANGE"/>
   <int value="344" label="WEB_VIEW_INTERNAL_ON_MESSAGE"/>
   <int value="345" label="EXTENSION_VIEW_INTERNAL_ON_LOAD_COMMIT"/>
   <int value="346" label="RUNTIME_ON_REQUEST"/>
@@ -21084,6 +21087,8 @@
   <int value="14" label="Invalid timing IPC (invalid timing)"/>
   <int value="15"
       label="Subframe navigation start before main frame navigation start"/>
+  <int value="16"
+      label="IPC received from subframe while not tracking a committed load"/>
 </enum>
 
 <enum name="InterruptReason">
@@ -23579,6 +23584,7 @@
   <int value="-10709540"
       label="OmniboxUIExperimentHideSuggestionUrlScheme:enabled"/>
   <int value="-5052940" label="enable-simplified-fullscreen"/>
+  <int value="-3093629" label="DcheckIsFatal:disabled"/>
   <int value="-2953333" label="AndroidHistoryManager:disabled"/>
   <int value="-2371418" label="disable-display-list-2d-canvas"/>
   <int value="0" label="BAD_FLAG_FORMAT">
@@ -23794,6 +23800,7 @@
   <int value="651844675" label="EasyUnlockPromotions:enabled"/>
   <int value="652561231" label="CustomContextMenu:enabled"/>
   <int value="659086147" label="OverlayScrollbarFlashWhenMouseEnter:enabled"/>
+  <int value="679931272" label="DcheckIsFatal:enabled"/>
   <int value="684806628" label="TranslateLanguageByULP:disabled"/>
   <int value="685916283" label="enable-zip-archiver-on-file-manager"/>
   <int value="687838135" label="ThirdPartyDoodles:disabled"/>
@@ -28132,6 +28139,18 @@
   </int>
 </enum>
 
+<enum name="OfflinePrefetchPageImportResult">
+  <summary>
+    All possible outcomes of an attempt to import a prefetched page archive into
+    the offline page model.
+  </summary>
+  <int value="0" label="Success"/>
+  <int value="1" label="Unknown error"/>
+  <int value="2" label="File move error"/>
+  <int value="3" label="Offline store failure"/>
+  <int value="4" label="Offline item already exists"/>
+</enum>
+
 <enum name="OfflineStatus">
   <obsolete>
     Deprecated 4/2015.
@@ -30253,6 +30272,7 @@
   <int value="12" label="PERMISSION_BUBBLE_PERMISSION_FLASH"/>
   <int value="13" label="PERMISSION_MEDIASTREAM_MIC"/>
   <int value="14" label="PERMISSION_MEDIASTREAM_CAMERA"/>
+  <int value="15" label="PERMISSION_ACCESSIBILITY_EVENTS"/>
 </enum>
 
 <enum name="PermissionStatus">
@@ -39500,6 +39520,7 @@
   <int value="6" label="HTTP authentication dialog was suppressed in VR"/>
   <int value="7" label="Download permission was suppressed in VR"/>
   <int value="8" label="File access permission was suppressed in VR"/>
+  <int value="9" label="Password manager was disabled in VR"/>
 </enum>
 
 <enum name="VRUnsupportedMode">
@@ -39877,6 +39898,12 @@
   <int value="2" label="Previously in the cache"/>
 </enum>
 
+<enum name="WebFontInstantiationResult">
+  <int value="0" label="Error instantiating variable font, falling back"/>
+  <int value="1" label="Success conventional web font"/>
+  <int value="2" label="Success variable web font"/>
+</enum>
+
 <enum name="WebFontInterventionResult">
   <int value="0" label="Wasn't triggered, and does not time out"/>
   <int value="1" label="Wasn't triggered, but time out"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index e0622b2f7..6d4458c 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -6084,6 +6084,16 @@
   </summary>
 </histogram>
 
+<histogram name="Blink.Fonts.VariableFontsRatio"
+    enum="WebFontInstantiationResult">
+  <owner>drott@chromium.org</owner>
+  <summary>
+    Tracks adoption ratio of variable fonts compared to conventional (in the
+    sense of non-variable) web fonts.  Recorded at the time of instantiating a
+    Skia SkTypeface from the successfully decoded web font blob.
+  </summary>
+</histogram>
+
 <histogram name="Blink.Gesture.Merged" enum="GestureMergeState">
   <owner>jyasskin@chromium.org</owner>
   <owner>domenic@google.com</owner>
@@ -14446,6 +14456,22 @@
   </summary>
 </histogram>
 
+<histogram name="DNS.StaleHostResolver.RestoreSizeOnCacheMiss">
+  <owner>mgersh@chromium.org</owner>
+  <summary>
+    When a DNS request made through StaleHostResolver has no stale cached result
+    available, the number of host cache entries that were restored from prefs.
+  </summary>
+</histogram>
+
+<histogram name="DNS.StaleHostResolver.SizeOnCacheMiss">
+  <owner>mgersh@chromium.org</owner>
+  <summary>
+    When a DNS request made through StaleHostResolver has no stale cached result
+    available, the number of entries in the host cache.
+  </summary>
+</histogram>
+
 <histogram name="DNS.StaleHostResolver.StaleAddressListDelta"
     enum="DNS.AddressListDeltaType">
   <owner>mgersh@chromium.org</owner>
@@ -15405,6 +15431,14 @@
   <summary>Types of images that are downloaded.</summary>
 </histogram>
 
+<histogram name="Download.ContentLength.Parallelizable" units="KB">
+  <owner>qinmin@chromium.org</owner>
+  <summary>
+    File size calculated from the content-length header of successfully
+    completed Parallelizable downloads.
+  </summary>
+</histogram>
+
 <histogram name="Download.ContentType" enum="DownloadContentType">
   <obsolete>
     Deprecated 03/2017, and replaced by Download.Start.ContentType.
@@ -25434,6 +25468,14 @@
   </summary>
 </histogram>
 
+<histogram name="GPU.Sandbox.InitializedSuccessfully" enum="BooleanSuccess">
+  <owner>piman@chromium.org</owner>
+  <summary>
+    Whether or not the GPU sandbox properly initialized. Failures are typically
+    platform- and driver-specific (e.g. driver creating threads on Linux).
+  </summary>
+</histogram>
+
 <histogram name="GPU.setIsAcceleratedCompositingActive"
     enum="GPUsetIsAcceleratedCompositingActive">
   <owner>vmiura@chromium.org</owner>
@@ -30274,6 +30316,19 @@
   </summary>
 </histogram>
 
+<histogram name="Media.Audio.Render.OutputDeviceAuthorizationTime" units="ms">
+  <owner>maxmorin@chromium.org</owner>
+  <summary>
+    Similar to Media.Audio.OutputDeviceAuthorizationTime, this histogram
+    measures the time required for device authorization, but it is measured on
+    the renderer side when AudioOutputDevice calls RequestDeviceAuthorization on
+    the IO thread until it receives OnDeviceAuthorized, also on the IO thread.
+    Note that an authorization timeout will cause OnDeviceAuthorized to be
+    called, so for platforms that use a timeout, very few times will be above
+    the timeout value.
+  </summary>
+</histogram>
+
 <histogram name="Media.Audio.Render.OutputDeviceAuthorizationTimedOut"
     enum="BooleanTimedOut">
   <owner>olka@chromium.org</owner>
@@ -50385,6 +50440,15 @@
   </summary>
 </histogram>
 
+<histogram name="OfflinePages.Prefetching.OfflinePageImportResult"
+    enum="OfflinePrefetchPageImportResult">
+  <owner>carlosk@chromium.org</owner>
+  <summary>
+    Final result of an attempt to import a prefetched article into the Offline
+    Pages system.
+  </summary>
+</histogram>
+
 <histogram name="OfflinePages.RedirectResult" enum="OfflinePagesRedirectResult">
   <obsolete>
     Deprecated 8/2016. Use OfflinePages.RequestResult instead.
@@ -75234,6 +75298,16 @@
   <summary>The outcome of Entry::ReadData in the simple cache.</summary>
 </histogram>
 
+<histogram base="true" name="SimpleCache.ReadStream1FromPrefetched"
+    enum="Boolean">
+  <owner>morlovich@chromium.org</owner>
+  <summary>
+    Whether a read from stream 1 (conventionally used for payload body) was
+    satisfied from prefetched data. Reported only on the first read operation on
+    the stream (including if there are multiple readers, or even some writers).
+  </summary>
+</histogram>
+
 <histogram base="true" name="SimpleCache.StaleIndexExtraEntryCount"
     units="entries">
   <owner>gavinp@chromium.org</owner>
@@ -75316,6 +75390,14 @@
   </summary>
 </histogram>
 
+<histogram base="true" name="SimpleCache.SyncOpenDidPrefetch" enum="Boolean">
+  <owner>morlovich@chromium.org</owner>
+  <summary>
+    Whether an attempt was made to prefetch the entire file when executing
+    disk_cache::Backend::OpenEntry.
+  </summary>
+</histogram>
+
 <histogram base="true" name="SimpleCache.SyncOpenEntryAge" units="hours">
   <owner>gavinp@chromium.org</owner>
   <summary>
@@ -81609,11 +81691,15 @@
   <owner>fmeawad@chromium.org</owner>
   <summary>
     The expected queueing duration of tasks in a foreground tab when the browser
-    is opening background tabs but not during session restore. The metric
-    reflects the responsiveness of a tab. A lower value means the tab will
-    respond to inputs faster. This metric is equal to
-    RendererScheduler.ExpectedTaskQueueingDuration. It is emitted once for all
-    tasks in each 1000-ms window.
+    is in background tab opening session, which is the duration from the time
+    when the browser starts to open background tabs until the time when browser
+    has finished loading those tabs or paused loading due to memory pressure. A
+    new session starts when the browser resumes loading background tabs when
+    memory pressure returns to normal. The metric reflects the responsiveness of
+    a tab. A lower value means the tab will respond to inputs faster. This
+    metric is equal to RendererScheduler.ExpectedTaskQueueingDuration. It is
+    emitted once for all tasks in each 1000-ms window. The metric is not
+    recorded when the session overlaps with session restore.
   </summary>
 </histogram>
 
@@ -81622,13 +81708,16 @@
   <owner>zhenw@chromium.org</owner>
   <summary>
     The loading state of a tab at the time the user switches to it when the
-    browser is opening background tabs. Backround tab opening excludes session
-    restore; this metric is tracked separately in that case
-    (TabManager.SessionRestore.SwitchToTab). The metric is only recorded when a
-    tab is switched to from another tab within the same tabstrip. As a result,
-    the case when switching between different windows is not included, either
-    between two tabs in different browser windows, or when switching to a
-    different application and switching back to the browser.
+    browser is in background tab opening session, which is the duration from the
+    time when the browser starts to open background tabs until the time when
+    browser has finished loading those tabs or paused loading due to memory
+    pressure. A new session starts when the browser resumes loading background
+    tabs when memory pressure returns to normal. The metric is only recorded
+    when a tab is switched to from another tab within the same tabstrip. As a
+    result, the case when switching between different windows is not included,
+    either between two tabs in different browser windows, or when switching to a
+    different application and switching back to the browser. The metric is not
+    recorded when the session overlaps with session restore.
   </summary>
 </histogram>
 
@@ -81721,22 +81810,132 @@
 </histogram>
 
 <histogram
+    name="TabManager.Experimental.BackgroundTabOpening.CompressedPagesPerSecond"
+    units="pages/s">
+  <owner>fmeawad@chromium.org</owner>
+  <summary>
+    The number of pages compressed per second when opening background tabs. This
+    is recorded at the end of background tab opening session as an average over
+    the entire period, which is defined as the duration from the time when the
+    browser starts to open background tabs until the time when browser has
+    finished loading those tabs or paused loading due to memory pressure. A new
+    session starts when the browser resumes loading background tabs when memory
+    pressure returns to normal. The metric is not recorded when the session
+    overlaps with session restore. Only recorded on macOS. Warning: This metric
+    is a ratio and the session interval differs for each session. It is hard to
+    tell if it is average rate for each second in the interval or it has a huge
+    spike.
+  </summary>
+</histogram>
+
+<histogram
+    name="TabManager.Experimental.BackgroundTabOpening.DecompressedPagesPerSecond"
+    units="pages/s">
+  <owner>fmeawad@chromium.org</owner>
+  <summary>
+    The number of pages decompressed per second when opening background tabs.
+    This is recorded at the end of background tab opening session as an average
+    over the entire period, which is defined as the duration from the time when
+    the browser starts to open background tabs until the time when browser has
+    finished loading those tabs or paused loading due to memory pressure. A new
+    session starts when the browser resumes loading background tabs when memory
+    pressure returns to normal. The metric is not recorded when the session
+    overlaps with session restore. Only recorded on macOS. Warning: This metric
+    is a ratio and the session interval differs for each session. It is hard to
+    tell if it is average rate for each second in the interval or it has a huge
+    spike.
+  </summary>
+</histogram>
+
+<histogram name="TabManager.Experimental.BackgroundTabOpening.SwapInPerSecond"
+    units="swaps/s">
+  <owner>fmeawad@chromium.org</owner>
+  <summary>
+    The number of swap-ins per second when opening background tabs. This is
+    recorded at the end of background tab opening session as an average over the
+    entire period, which is defined as the duration from the time when the
+    browser starts to open background tabs until the time when browser has
+    finished loading those tabs or paused loading due to memory pressure. A new
+    session starts when the browser resumes loading background tabs when memory
+    pressure returns to normal. The metric is not recorded when the session
+    overlaps with session restore. Warning: This metric is a ratio and the
+    session interval differs for each session. It is hard to tell if it is
+    average rate for each second in the interval or it has a huge spike.
+  </summary>
+</histogram>
+
+<histogram name="TabManager.Experimental.BackgroundTabOpening.SwapOutPerSecond"
+    units="swaps/s">
+  <owner>fmeawad@chromium.org</owner>
+  <summary>
+    The number of swap-outs per second when opening background tabs. This is
+    recorded at the end of background tab opening session as an average over the
+    entire period, which is defined as the duration from the time when the
+    browser starts to open background tabs until the time when browser has
+    finished loading those tabs or paused loading due to memory pressure. A new
+    session starts when the browser resumes loading background tabs when memory
+    pressure returns to normal. The metric is not recorded when the session
+    overlaps with session restore. Warning: This metric is a ratio and the
+    session interval differs for each session. It is hard to tell if it is
+    average rate for each second in the interval or it has a huge spike.
+  </summary>
+</histogram>
+
+<histogram
     name="TabManager.Experimental.BackgroundTabOpening.TabSwitchLoadTime"
     units="ms">
   <owner>zhenw@chromium.org</owner>
   <summary>
-    The tab load time of a tab that is switched to when the browser is opening
-    background tabs. Backround tab opening excludes session restore; this metric
-    is tracked separately in that case
-    (TabManager.Experimental.SessionRestore.TabSwitchLoadTime). Tab load time is
-    defined as the time between when the user switches to a backround tab, and
-    the time when that tab finishes loading in the foreground. If the user
-    switches away before the tab finishes loading, a metric will not be recorded
-    unless the user switches back, in which case the tab load time is measured
-    from that point in time. The metric is only recorded when a tab is switched
-    to from another tab within the same tabstrip. As a result, the initial
-    forground tab is not included in this metric since it was not switched to
-    from another tab.
+    The tab load time of a tab that is switched to when the browser is in
+    background tab opening session, which is the duration from the time when the
+    browser starts to open background tabs until the time when browser has
+    finished loading those tabs or paused loading due to memory pressure. A new
+    session starts when the browser resumes loading background tabs when memory
+    pressure returns to normal. Tab load time is defined as the time between
+    when the user switches to a backround tab, and the time when that tab
+    finishes loading in the foreground. If the user switches away before the tab
+    finishes loading, a metric will not be recorded unless the user switches
+    back, in which case the tab load time is measured from that point in time.
+    The metric is only recorded when a tab is switched to from another tab
+    within the same tabstrip. As a result, the initial forground tab is not
+    included in this metric since it was not switched to from another tab. The
+    metric is not recorded when the session overlaps with session restore.
+  </summary>
+</histogram>
+
+<histogram
+    name="TabManager.Experimental.SessionRestore.CompressedPagesPerSecond"
+    units="pages/s">
+  <owner>fmeawad@chromium.org</owner>
+  <summary>
+    The number of pages compressed per second during session restore. Recorded
+    at the end of session restore as an average over the entire period, defined
+    as the period of time when session restore is actively loading tabs, which
+    ends when either all tabs have been loaded and their pages rendered, or tab
+    loading needs to be deferred in cases where the system is under memory
+    pressure. The metric is not recorded when the session overlaps with
+    background tab opening session. Only recorded on macOS. Warning: This metric
+    is a ratio and the session interval differs for each session. It is hard to
+    tell if it is average rate for each second in the interval or it has a huge
+    spike.
+  </summary>
+</histogram>
+
+<histogram
+    name="TabManager.Experimental.SessionRestore.DecompressedPagesPerSecond"
+    units="pages/s">
+  <owner>fmeawad@chromium.org</owner>
+  <summary>
+    The number of pages decompressed per second during session restore. Recorded
+    at the end of session restore as an average over the entire period, defined
+    as the period of time when session restore is actively loading tabs, which
+    ends when either all tabs have been loaded and their pages rendered, or tab
+    loading needs to be deferred in cases where the system is under memory
+    pressure. The metric is not recorded when the session overlaps with
+    background tab opening session. Only recorded on macOS. Warning: This metric
+    is a ratio and the session interval differs for each session. It is hard to
+    tell if it is average rate for each second in the interval or it has a huge
+    spike.
   </summary>
 </histogram>
 
@@ -81773,6 +81972,38 @@
   </summary>
 </histogram>
 
+<histogram name="TabManager.Experimental.SessionRestore.SwapInPerSecond"
+    units="swaps/s">
+  <owner>fmeawad@chromium.org</owner>
+  <summary>
+    The number of swap-ins per second during session restore. Recorded at the
+    end of session restore as an average over the entire period, defined as the
+    period of time when session restore is actively loading tabs, which ends
+    when either all tabs have been loaded and their pages rendered, or tab
+    loading needs to be deferred in cases where the system is under memory
+    pressure. The metric is not recorded when the session overlaps with
+    background tab opening session. Warning: This metric is a ratio and the
+    session interval differs for each session. It is hard to tell if it is
+    average rate for each second in the interval or it has a huge spike.
+  </summary>
+</histogram>
+
+<histogram name="TabManager.Experimental.SessionRestore.SwapOutPerSecond"
+    units="swaps/s">
+  <owner>fmeawad@chromium.org</owner>
+  <summary>
+    The number of swap-outs per second during session restore. Recorded at the
+    end of session restore as an average over the entire period, defined as the
+    period of time when session restore is actively loading tabs, which ends
+    when either all tabs have been loaded and their pages rendered, or tab
+    loading needs to be deferred in cases where the system is under memory
+    pressure. The metric is not recorded when the session overlaps with
+    background tab opening session. Warning: This metric is a ratio and the
+    session interval differs for each session. It is hard to tell if it is
+    average rate for each second in the interval or it has a huge spike.
+  </summary>
+</histogram>
+
 <histogram name="TabManager.Experimental.SessionRestore.TabSwitchLoadTime"
     units="ms">
   <owner>fmeawad@chromium.org</owner>
@@ -81788,7 +82019,9 @@
     metric since it was not switched to from another tab. The metric is only
     recorded when session restore is actively loading tabs, which ends when
     either all tabs have been loaded and their pages rendered, or tab loading
-    needs to be deferred in cases where the system is under memory pressure.
+    needs to be deferred in cases where the system is under memory pressure. The
+    metric is not recorded when the session overlaps with background tab opening
+    session.
   </summary>
 </histogram>
 
@@ -81851,6 +82084,10 @@
 
 <histogram name="TabManager.SessionRestore.CompressedPagesPerSecond"
     units="pages/s">
+  <obsolete>
+    Deprecated 08/2017, and replaced by
+    TabManager.Experimental.SessionRestore.CompressedPagesPerSecond.
+  </obsolete>
   <owner>fmeawad@chromium.org</owner>
   <summary>
     The number of pages compressed per second during session restore. Recorded
@@ -81864,6 +82101,10 @@
 
 <histogram name="TabManager.SessionRestore.DecompressedPagesPerSecond"
     units="pages/s">
+  <obsolete>
+    Deprecated 08/2017, and replaced by
+    TabManager.Experimental.SessionRestore.DecompressedPagesPerSecond.
+  </obsolete>
   <owner>fmeawad@chromium.org</owner>
   <summary>
     The number of pages decompressed per second during session restore. Recorded
@@ -81884,11 +82125,16 @@
     restore. This metric reflects the responsiveness of a tab. A lower value
     means the tab will respond to inputs faster. This metric is equal to
     RendererScheduler.ExpectedTaskQueueingDuration. It is emitted once for all
-    tasks in each 1000-ms window.
+    tasks in each 1000-ms window. The metric is not recorded when the session
+    overlaps with background tab opening session.
   </summary>
 </histogram>
 
 <histogram name="TabManager.SessionRestore.SwapInPerSecond" units="swaps/s">
+  <obsolete>
+    Deprecated 08/2017, and replaced by
+    TabManager.Experimental.SessionRestore.SwapInPerSecond.
+  </obsolete>
   <owner>fmeawad@chromium.org</owner>
   <summary>
     The number of swap-ins per second during session restore. Recorded at the
@@ -81901,6 +82147,10 @@
 </histogram>
 
 <histogram name="TabManager.SessionRestore.SwapOutPerSecond" units="swaps/s">
+  <obsolete>
+    Deprecated 08/2017, and replaced by
+    TabManager.Experimental.SessionRestore.SwapOutPerSecond.
+  </obsolete>
   <owner>fmeawad@chromium.org</owner>
   <summary>
     The number of swap-outs per second during session restore. Recorded at the
@@ -81925,7 +82175,8 @@
     switching back to the browser. The metric is only recorded when session
     restore is actively loading tabs, which ends when either all tabs have been
     loaded and their pages rendered, or tab loading needs to be deferred in
-    cases where the system is under memory pressure.
+    cases where the system is under memory pressure. The metric is not recorded
+    when the session overlaps with background tab opening session.
   </summary>
 </histogram>
 
@@ -87029,6 +87280,32 @@
   </summary>
 </histogram>
 
+<histogram name="WebApk.Install.AvailableSpace.Fail" units="MB">
+  <owner>hanxi@chromium.org</owner>
+  <owner>ranj@chromium.org</owner>
+  <owner>yfriedman@chromium.org</owner>
+  <summary>
+    Records the available space that can be used when installing a WebAPK from
+    Google Play fails. The space recorded is the available space beyond the
+    system's minimum free space threshold, with a range between -1000 and 500
+    MB. Negative values mean that there is less free space available than the
+    system's minimum, by the given amount.
+  </summary>
+</histogram>
+
+<histogram name="WebApk.Install.AvailableSpace.Success" units="MB">
+  <owner>hanxi@chromium.org</owner>
+  <owner>ranj@chromium.org</owner>
+  <owner>yfriedman@chromium.org</owner>
+  <summary>
+    Records the available space that can be used when installing a WebAPK from
+    Google Play succeeds. The space recorded is the available space beyond the
+    system's minimum free space threshold, with a range between -1000 and 500
+    MB. Negative values mean that there is less free space available than the
+    system's minimum, by the given amount.
+  </summary>
+</histogram>
+
 <histogram name="WebApk.Install.GooglePlayBindDuration" units="ms">
   <owner>hanxi@chromium.org</owner>
   <owner>pkotwicz@chromium.org</owner>
@@ -92632,6 +92909,7 @@
   <affected-histogram name="SimpleCache.QueueLatency.OpenEntry"/>
   <affected-histogram name="SimpleCache.ReadIsParallelizable"/>
   <affected-histogram name="SimpleCache.ReadResult"/>
+  <affected-histogram name="SimpleCache.ReadStream1FromPrefetched"/>
   <affected-histogram name="SimpleCache.StaleIndexExtraEntryCount"/>
   <affected-histogram name="SimpleCache.StaleIndexMissedEntryCount"/>
   <affected-histogram name="SimpleCache.StaleIndexQuality"/>
@@ -92646,6 +92924,7 @@
   <affected-histogram name="SimpleCache.SyncCreateResult_WithIndex"/>
   <affected-histogram name="SimpleCache.SyncCreateResult_WithoutIndex"/>
   <affected-histogram name="SimpleCache.SyncKeySHA256Result"/>
+  <affected-histogram name="SimpleCache.SyncOpenDidPrefetch"/>
   <affected-histogram name="SimpleCache.SyncOpenEntryAge"/>
   <affected-histogram name="SimpleCache.SyncOpenPlatformFileError"/>
   <affected-histogram name="SimpleCache.SyncOpenPlatformFileError_WithIndex"/>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index 0da7eef..87022da 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -641,6 +641,17 @@
   </metric>
 </event>
 
+<event name="OfflinePages.SavePageRequested">
+  <owner>petewil@chromium.org</owner>
+  <metric name="RequestedFromForeground">
+    <summary>
+      Metrics that measure which URLs the user is requesting offline page copies
+      of, and whether they were requested from the foreground or background UI.
+      The value is 1 if requested from the foreground, 0 from background.
+    </summary>
+  </metric>
+</event>
+
 <event name="PageDomainInfo">
   <owner>uthakore@chromium.org</owner>
   <owner>invernizzi@chromium.org</owner>
diff --git a/tools/perf/benchmarks/dummy_benchmark.py b/tools/perf/benchmarks/dummy_benchmark.py
index 092cf40..248314d 100644
--- a/tools/perf/benchmarks/dummy_benchmark.py
+++ b/tools/perf/benchmarks/dummy_benchmark.py
@@ -16,6 +16,7 @@
 from telemetry import story
 from telemetry.value import scalar
 from telemetry.page import legacy_page_test
+from telemetry.web_perf import timeline_based_measurement
 
 from page_sets import dummy_story_set
 
@@ -74,3 +75,26 @@
       def SetExpectations(self):
         pass # Nothing disabled.
     return StoryExpectations()
+
+
+@benchmark.Owner(emails=['eakuefner@chromium.org', 'simonhatch@chromium.org'])
+class DummyBenchmarkThree(perf_benchmark.PerfBenchmark):
+  """A test benchmark for outputting histograms."""
+  page_set = dummy_story_set.DummyStorySet
+
+  def CreateCoreTimelineBasedMeasurementOptions(self):
+    options = timeline_based_measurement.Options(
+        timeline_based_measurement.DEBUG_OVERHEAD_LEVEL)
+    options.SetTimelineBasedMetrics(['sampleMetric'])
+    return options
+
+  @classmethod
+  def Name(cls):
+    return 'dummy_benchmark.histogram_benchmark_1'
+
+  def GetExpectations(self):
+    class StoryExpectations(story.expectations.StoryExpectations):
+      def SetExpectations(self):
+        self.PermanentlyDisableBenchmark(
+            [story.expectations.ALL], 'crbug.com/756210')
+    return StoryExpectations()
diff --git a/tools/perf/chromium.perf.fyi.extras.json b/tools/perf/chromium.perf.fyi.extras.json
index 8be67d5..32457afe 100644
--- a/tools/perf/chromium.perf.fyi.extras.json
+++ b/tools/perf/chromium.perf.fyi.extras.json
@@ -28,5 +28,30 @@
         }
       }
     ]
+  },
+  "Histogram Pipeline Linux Perf": {
+    "isolated_scripts": [
+      {
+        "args": [
+          "dummy_benchmark.histogram_benchmark_1",
+          "-v",
+          "--upload-results",
+          "--output-format=histograms",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "dummy_benchmark.histogram_benchmark_1",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      }
+    ]
   }
 }
diff --git a/tools/perf/core/benchmark_sharding_map.json b/tools/perf/core/benchmark_sharding_map.json
index bb6a9e0..de73de9 100644
--- a/tools/perf/core/benchmark_sharding_map.json
+++ b/tools/perf/core/benchmark_sharding_map.json
@@ -73,6 +73,7 @@
     "build14-b1--device2": {
       "benchmarks": [
         "dummy_benchmark.noisy_benchmark_1",
+        "dummy_benchmark.histogram_benchmark_1",
         "jetstream",
         "page_cycler_v2.intl_hi_ru",
         "smoothness.tough_texture_upload_cases",
@@ -304,6 +305,7 @@
     "build74-b1--device2": {
       "benchmarks": [
         "dummy_benchmark.noisy_benchmark_1",
+        "dummy_benchmark.histogram_benchmark_1",
         "jetstream",
         "page_cycler_v2.intl_hi_ru",
         "smoothness.tough_texture_upload_cases",
@@ -515,6 +517,7 @@
       "benchmarks": [
         "blink_perf.shadow_dom",
         "dummy_benchmark.noisy_benchmark_1",
+        "dummy_benchmark.histogram_benchmark_1",
         "media.tough_video_cases_tbmv2",
         "memory.long_running_idle_gmail_background_tbmv2",
         "smoothness.gpu_rasterization.tough_scrolling_cases",
@@ -741,6 +744,7 @@
     "build16-b1--device2": {
       "benchmarks": [
         "dummy_benchmark.noisy_benchmark_1",
+        "dummy_benchmark.histogram_benchmark_1",
         "jetstream",
         "page_cycler_v2.intl_hi_ru",
         "smoothness.tough_texture_upload_cases",
@@ -952,6 +956,7 @@
       "benchmarks": [
         "blink_perf.shadow_dom",
         "dummy_benchmark.noisy_benchmark_1",
+        "dummy_benchmark.histogram_benchmark_1",
         "media.tough_video_cases_tbmv2",
         "memory.long_running_idle_gmail_background_tbmv2",
         "smoothness.gpu_rasterization.tough_scrolling_cases",
@@ -1122,6 +1127,7 @@
     "build10-b1--device2": {
       "benchmarks": [
         "dummy_benchmark.noisy_benchmark_1",
+        "dummy_benchmark.histogram_benchmark_1",
         "jetstream",
         "page_cycler_v2.intl_hi_ru",
         "smoothness.tough_scrolling_cases",
@@ -1415,6 +1421,7 @@
     "build18-b1--device3": {
       "benchmarks": [
         "dummy_benchmark.noisy_benchmark_1",
+        "dummy_benchmark.histogram_benchmark_1",
         "memory.top_10_mobile",
         "smoothness.gpu_rasterization.tough_path_rendering_cases",
         "smoothness.pathological_mobile_sites",
@@ -1640,6 +1647,7 @@
     "build248-m4--device2": {
       "benchmarks": [
         "dummy_benchmark.noisy_benchmark_1",
+        "dummy_benchmark.histogram_benchmark_1",
         "jetstream",
         "page_cycler_v2.intl_hi_ru",
         "smoothness.tough_texture_upload_cases",
@@ -1827,6 +1835,7 @@
         "blink_perf.canvas",
         "blink_perf.owp_storage",
         "dummy_benchmark.noisy_benchmark_1",
+        "dummy_benchmark.histogram_benchmark_1",
         "loading.desktop",
         "octane",
         "oortonline_tbmv2",
@@ -1997,6 +2006,7 @@
         "blink_perf.canvas",
         "blink_perf.owp_storage",
         "dummy_benchmark.noisy_benchmark_1",
+        "dummy_benchmark.histogram_benchmark_1",
         "loading.desktop",
         "octane",
         "oortonline_tbmv2",
@@ -2164,6 +2174,7 @@
         "blink_perf.canvas",
         "blink_perf.owp_storage",
         "dummy_benchmark.noisy_benchmark_1",
+        "dummy_benchmark.histogram_benchmark_1",
         "loading.desktop",
         "octane",
         "oortonline_tbmv2",
@@ -2330,6 +2341,7 @@
         "blink_perf.canvas",
         "blink_perf.owp_storage",
         "dummy_benchmark.noisy_benchmark_1",
+        "dummy_benchmark.histogram_benchmark_1",
         "loading.desktop",
         "octane",
         "oortonline_tbmv2",
@@ -2498,6 +2510,7 @@
         "blink_perf.canvas",
         "blink_perf.owp_storage",
         "dummy_benchmark.noisy_benchmark_1",
+        "dummy_benchmark.histogram_benchmark_1",
         "loading.desktop",
         "octane",
         "oortonline_tbmv2",
@@ -2665,6 +2678,7 @@
         "blink_perf.canvas",
         "blink_perf.owp_storage",
         "dummy_benchmark.noisy_benchmark_1",
+        "dummy_benchmark.histogram_benchmark_1",
         "loading.desktop",
         "octane",
         "oortonline_tbmv2",
@@ -2868,6 +2882,7 @@
         "blink_perf.canvas",
         "blink_perf.owp_storage",
         "dummy_benchmark.noisy_benchmark_1",
+        "dummy_benchmark.histogram_benchmark_1",
         "loading.desktop",
         "octane",
         "oortonline_tbmv2",
@@ -3085,6 +3100,7 @@
         "battor.steady_state",
         "blink_perf.paint",
         "dummy_benchmark.noisy_benchmark_1",
+        "dummy_benchmark.histogram_benchmark_1",
         "oortonline_tbmv2",
         "rasterize_and_record_micro.top_25",
         "smoothness.tough_webgl_cases",
@@ -3234,6 +3250,7 @@
         "blink_perf.canvas",
         "blink_perf.owp_storage",
         "dummy_benchmark.noisy_benchmark_1",
+        "dummy_benchmark.histogram_benchmark_1",
         "loading.desktop",
         "octane",
         "oortonline_tbmv2",
@@ -3487,6 +3504,7 @@
         "battor.steady_state",
         "blink_perf.paint",
         "dummy_benchmark.noisy_benchmark_1",
+        "dummy_benchmark.histogram_benchmark_1",
         "oortonline_tbmv2",
         "rasterize_and_record_micro.top_25",
         "smoothness.tough_webgl_cases",
@@ -3636,6 +3654,7 @@
         "blink_perf.canvas",
         "blink_perf.owp_storage",
         "dummy_benchmark.noisy_benchmark_1",
+        "dummy_benchmark.histogram_benchmark_1",
         "loading.desktop",
         "octane",
         "oortonline_tbmv2",
@@ -3803,6 +3822,7 @@
         "blink_perf.canvas",
         "blink_perf.owp_storage",
         "dummy_benchmark.noisy_benchmark_1",
+        "dummy_benchmark.histogram_benchmark_1",
         "loading.desktop",
         "octane",
         "oortonline_tbmv2",
@@ -3970,6 +3990,7 @@
         "blink_perf.canvas",
         "blink_perf.owp_storage",
         "dummy_benchmark.noisy_benchmark_1",
+        "dummy_benchmark.histogram_benchmark_1",
         "loading.desktop",
         "octane",
         "oortonline_tbmv2",
@@ -4137,6 +4158,7 @@
         "blink_perf.canvas",
         "blink_perf.owp_storage",
         "dummy_benchmark.noisy_benchmark_1",
+        "dummy_benchmark.histogram_benchmark_1",
         "loading.desktop",
         "octane",
         "oortonline_tbmv2",
@@ -4304,6 +4326,7 @@
         "blink_perf.canvas",
         "blink_perf.owp_storage",
         "dummy_benchmark.noisy_benchmark_1",
+        "dummy_benchmark.histogram_benchmark_1",
         "loading.desktop",
         "octane",
         "oortonline_tbmv2",
@@ -4471,6 +4494,7 @@
         "blink_perf.canvas",
         "blink_perf.owp_storage",
         "dummy_benchmark.noisy_benchmark_1",
+        "dummy_benchmark.histogram_benchmark_1",
         "loading.desktop",
         "octane",
         "oortonline_tbmv2",
@@ -4638,6 +4662,7 @@
         "blink_perf.canvas",
         "blink_perf.owp_storage",
         "dummy_benchmark.noisy_benchmark_1",
+        "dummy_benchmark.histogram_benchmark_1",
         "loading.desktop",
         "octane",
         "oortonline_tbmv2",
@@ -4791,6 +4816,7 @@
     "dromaeo.domcoremodify",
     "dromaeo.domcorequery",
     "dromaeo.domcoretraverse",
+    "dummy_benchmark.histogram_benchmark_1",
     "dummy_benchmark.noisy_benchmark_1",
     "dummy_benchmark.stable_benchmark_1",
     "image_decoding.image_decoding_measurement",
diff --git a/tools/perf/core/perf_data_generator.py b/tools/perf/core/perf_data_generator.py
index 2a58476..d141018 100755
--- a/tools/perf/core/perf_data_generator.py
+++ b/tools/perf/core/perf_data_generator.py
@@ -577,7 +577,8 @@
 def generate_isolate_script_entry(swarming_dimensions, test_args,
     isolate_name, step_name, ignore_task_failure,
     override_compile_targets=None,
-    swarming_timeout=None):
+    swarming_timeout=None,
+    io_timeout=None):
   result = {
     'args': test_args,
     'isolate_name': isolate_name,
@@ -593,7 +594,7 @@
       'expiration': 20 * 60 * 60, # 20 hour timeout for now (crbug.com/753367)
       'hard_timeout': swarming_timeout if swarming_timeout else 10800, # 3 hours
       'ignore_task_failure': ignore_task_failure,
-      'io_timeout': 10 * 60,
+      'io_timeout': io_timeout if io_timeout else 600, # 10 minutes
       'dimension_sets': swarming_dimensions,
       'upload_test_results': False,
     }
@@ -647,7 +648,8 @@
       swarming_dimensions, test_args, isolate_name,
       step_name, ignore_task_failure=ignore_task_failure,
       override_compile_targets=[isolate_name],
-      swarming_timeout=BENCHMARK_SWARMING_TIMEOUTS.get(benchmark_name))
+      swarming_timeout=BENCHMARK_SWARMING_TIMEOUTS.get(benchmark_name),
+      io_timeout=BENCHMARK_SWARMING_IO_TIMEOUTS.get(benchmark_name))
 
 
 def script_test_enabled_on_tester(master, test, tester_name, shard):
@@ -806,6 +808,12 @@
 }
 
 
+# Overrides the default 10m swarming I/O timeout.
+BENCHMARK_SWARMING_IO_TIMEOUTS = {
+    'jetstream': 1200, # 20 minutes
+}
+
+
 # Devices which are broken right now. Tests will not be scheduled on them.
 # Please add a comment with a bug for replacing the device.
 BLACKLISTED_DEVICES = []
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc
index c85b0945..57db017 100644
--- a/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -1311,6 +1311,33 @@
   return S_OK;
 }
 
+STDMETHODIMP AXPlatformNodeWin::get_groupPosition(LONG* group_level,
+                                                  LONG* similar_items_in_group,
+                                                  LONG* position_in_group) {
+  WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_GROUP_POSITION);
+  COM_OBJECT_VALIDATE_3_ARGS(group_level, similar_items_in_group,
+                             position_in_group);
+  AXPlatformNode::NotifyAddAXModeFlags(kScreenReaderAndHTMLAccessibilityModes);
+
+  *group_level = GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL);
+  *similar_items_in_group = GetIntAttribute(ui::AX_ATTR_SET_SIZE);
+  *position_in_group = GetIntAttribute(ui::AX_ATTR_POS_IN_SET);
+
+  if (*group_level == *similar_items_in_group == *position_in_group == 0)
+    return S_FALSE;
+  return S_OK;
+}
+
+STDMETHODIMP AXPlatformNodeWin::get_localizedExtendedRole(
+    BSTR* localized_extended_role) {
+  WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_LOCALIZED_EXTENDED_ROLE);
+  COM_OBJECT_VALIDATE_1_ARG(localized_extended_role);
+  AXPlatformNode::NotifyAddAXModeFlags(kScreenReaderAndHTMLAccessibilityModes);
+
+  return GetStringAttributeAsBstr(ui::AX_ATTR_ROLE_DESCRIPTION,
+                                  localized_extended_role);
+}
+
 //
 // IAccessible2 methods not implemented.
 //
@@ -1333,17 +1360,6 @@
   return E_NOTIMPL;
 }
 
-STDMETHODIMP AXPlatformNodeWin::get_groupPosition(LONG* group_level,
-                                                  LONG* similar_items_in_group,
-                                                  LONG* position_in_group) {
-  return E_NOTIMPL;
-}
-
-STDMETHODIMP AXPlatformNodeWin::get_localizedExtendedRole(
-    BSTR* localized_extended_role) {
-  return E_NOTIMPL;
-}
-
 STDMETHODIMP AXPlatformNodeWin::get_nExtendedStates(LONG* n_extended_states) {
   WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_N_EXTENDED_STATES);
   return E_NOTIMPL;
diff --git a/ui/accessibility/platform/ax_platform_node_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_win_unittest.cc
index c0dc48fd..8fcf2ee 100644
--- a/ui/accessibility/platform/ax_platform_node_win_unittest.cc
+++ b/ui/accessibility/platform/ax_platform_node_win_unittest.cc
@@ -2053,4 +2053,37 @@
   CheckIUnknownHasName(table_cell_4, L"4");
 }
 
+TEST_F(AXPlatformNodeWinTest, TestIAccessible2GetGroupPosition) {
+  AXNodeData root;
+  root.id = 1;
+  root.AddIntAttribute(AX_ATTR_HIERARCHICAL_LEVEL, 1);
+  root.AddIntAttribute(AX_ATTR_SET_SIZE, 1);
+  root.AddIntAttribute(AX_ATTR_POS_IN_SET, 1);
+  Init(root);
+
+  ScopedComPtr<IAccessible> root_obj(GetRootIAccessible());
+  ScopedComPtr<IAccessible2> iaccessible2 = ToIAccessible2(root_obj);
+  LONG level, similar, position;
+  EXPECT_EQ(S_OK, iaccessible2->get_groupPosition(&level, &similar, &position));
+  EXPECT_EQ(1, level);
+  EXPECT_EQ(1, similar);
+  EXPECT_EQ(1, position);
+
+  EXPECT_EQ(E_INVALIDARG,
+            iaccessible2->get_groupPosition(nullptr, nullptr, nullptr));
+}
+
+TEST_F(AXPlatformNodeWinTest, TestIAccessible2GetLocalizedExtendedRole) {
+  AXNodeData root;
+  root.id = 1;
+  root.AddStringAttribute(AX_ATTR_ROLE_DESCRIPTION, "extended role");
+  Init(root);
+
+  ScopedComPtr<IAccessible> root_obj(GetRootIAccessible());
+  ScopedComPtr<IAccessible2> iaccessible2 = ToIAccessible2(root_obj);
+  ScopedBstr role;
+  EXPECT_EQ(S_OK, iaccessible2->get_localizedExtendedRole(role.Receive()));
+  EXPECT_STREQ(L"extended role", role);
+}
+
 }  // namespace ui
diff --git a/ui/android/event_forwarder.cc b/ui/android/event_forwarder.cc
index 4fdd3c894..023bc6e 100644
--- a/ui/android/event_forwarder.cc
+++ b/ui/android/event_forwarder.cc
@@ -67,7 +67,7 @@
                                       jint android_tool_type_1,
                                       jint android_button_state,
                                       jint android_meta_state,
-                                      jboolean is_touch_handle_event) {
+                                      jboolean for_touch_handle) {
   ui::MotionEventAndroid::Pointer pointer0(
       pointer_id_0, pos_x_0, pos_y_0, touch_major_0, touch_minor_0,
       orientation_0, tilt_0, android_tool_type_0);
@@ -78,8 +78,9 @@
       env, motion_event.obj(), 1.f / view_->GetDipScale(), 0.f, 0.f, 0.f,
       time_ms, android_action, pointer_count, history_size, action_index,
       0 /* action_button */, android_button_state, android_meta_state,
-      raw_pos_x - pos_x_0, raw_pos_y - pos_y_0, &pointer0, &pointer1);
-  return view_->OnTouchEvent(event, is_touch_handle_event);
+      raw_pos_x - pos_x_0, raw_pos_y - pos_y_0, for_touch_handle, &pointer0,
+      &pointer1);
+  return view_->OnTouchEvent(event);
 }
 
 void EventForwarder::OnMouseEvent(JNIEnv* env,
@@ -107,7 +108,8 @@
       time_ms, android_action, 1 /* pointer_count */, 0 /* history_size */,
       0 /* action_index */, android_action_button, android_button_state,
       android_meta_state, 0 /* raw_offset_x_pixels */,
-      0 /* raw_offset_y_pixels */, &pointer, nullptr);
+      0 /* raw_offset_y_pixels */, false /* for_touch_handle */, &pointer,
+      nullptr);
   view_->OnMouseEvent(event);
 }
 
@@ -131,12 +133,12 @@
                               delta.InMicroseconds(), 1, 1000000, 50);
   ui::MotionEventAndroid::Pointer pointer(
       0, x, y, 0.0f /* touch_major */, 0.0f /* touch_minor */, 0.0f, 0.0f, 0);
-  ui::MotionEventAndroid event(env, nullptr, 1.f / view_->GetDipScale(),
-                               ticks_x, ticks_y, pixels_per_tick, time_ms,
-                               0 /* action */, 1 /* pointer_count */,
-                               0 /* history_size */, 0 /* action_index */, 0, 0,
-                               0, 0 /* raw_offset_x_pixels */,
-                               0 /* raw_offset_y_pixels */, &pointer, nullptr);
+  ui::MotionEventAndroid event(
+      env, nullptr, 1.f / view_->GetDipScale(), ticks_x, ticks_y,
+      pixels_per_tick, time_ms, 0 /* action */, 1 /* pointer_count */,
+      0 /* history_size */, 0 /* action_index */, 0, 0, 0,
+      0 /* raw_offset_x_pixels */, 0 /* raw_offset_y_pixels */,
+      false /* for_touch_handle */, &pointer, nullptr);
 
   view_->OnMouseWheelEvent(event);
 }
diff --git a/ui/android/view_android.cc b/ui/android/view_android.cc
index 91b31f9..915e09a7 100644
--- a/ui/android/view_android.cc
+++ b/ui/android/view_android.cc
@@ -403,20 +403,17 @@
   return client->OnDragEvent(*e);
 }
 
-bool ViewAndroid::OnTouchEvent(const MotionEventAndroid& event,
-                               bool for_touch_handle) {
-  return HitTest(
-      base::Bind(&ViewAndroid::SendTouchEventToClient, for_touch_handle), event,
-      event.GetPoint());
+bool ViewAndroid::OnTouchEvent(const MotionEventAndroid& event) {
+  return HitTest(base::Bind(&ViewAndroid::SendTouchEventToClient), event,
+                 event.GetPoint());
 }
 
 // static
-bool ViewAndroid::SendTouchEventToClient(bool for_touch_handle,
-                                         ViewClient* client,
+bool ViewAndroid::SendTouchEventToClient(ViewClient* client,
                                          const MotionEventAndroid& event,
                                          const gfx::PointF& point) {
   std::unique_ptr<MotionEventAndroid> e(event.CreateFor(point));
-  return client->OnTouchEvent(*e, for_touch_handle);
+  return client->OnTouchEvent(*e);
 }
 
 bool ViewAndroid::OnMouseEvent(const MotionEventAndroid& event) {
diff --git a/ui/android/view_android.h b/ui/android/view_android.h
index 577c313d..df1c438 100644
--- a/ui/android/view_android.h
+++ b/ui/android/view_android.h
@@ -189,7 +189,7 @@
   friend class ViewAndroidBoundsTest;
 
   bool OnDragEvent(const DragEventAndroid& event);
-  bool OnTouchEvent(const MotionEventAndroid& event, bool for_touch_handle);
+  bool OnTouchEvent(const MotionEventAndroid& event);
   bool OnMouseEvent(const MotionEventAndroid& event);
   bool OnMouseWheelEvent(const MotionEventAndroid& event);
 
@@ -210,8 +210,7 @@
   static bool SendDragEventToClient(ViewClient* client,
                                     const DragEventAndroid& event,
                                     const gfx::PointF& point);
-  static bool SendTouchEventToClient(bool for_touch_handle,
-                                     ViewClient* client,
+  static bool SendTouchEventToClient(ViewClient* client,
                                      const MotionEventAndroid& event,
                                      const gfx::PointF& point);
   static bool SendMouseEventToClient(ViewClient* client,
diff --git a/ui/android/view_android_unittests.cc b/ui/android/view_android_unittests.cc
index f3d077a..2205668 100644
--- a/ui/android/view_android_unittests.cc
+++ b/ui/android/view_android_unittests.cc
@@ -20,8 +20,7 @@
   TestViewClient() : handle_event_(true), called_(false) {}
 
   void SetHandleEvent(bool handle_event) { handle_event_ = handle_event; }
-  bool OnTouchEvent(const MotionEventAndroid& event,
-                    bool for_touch_handle) override {
+  bool OnTouchEvent(const MotionEventAndroid& event) override {
     called_ = true;
     return handle_event_;
   }
@@ -56,9 +55,9 @@
     ui::MotionEventAndroid::Pointer pointer0(0, x, y, 0, 0, 0, 0, 0);
     ui::MotionEventAndroid::Pointer pointer1(0, 0, 0, 0, 0, 0, 0, 0);
     ui::MotionEventAndroid event(nullptr, JavaParamRef<jobject>(nullptr), 1.f,
-                                 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+                                 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, false,
                                  &pointer0, &pointer1);
-    root_.OnTouchEvent(event, false);
+    root_.OnTouchEvent(event);
   }
 
   void ExpectHit(const TestViewClient& hitClient) {
diff --git a/ui/android/view_client.cc b/ui/android/view_client.cc
index 2fc2532f..007ff62d 100644
--- a/ui/android/view_client.cc
+++ b/ui/android/view_client.cc
@@ -6,8 +6,7 @@
 
 namespace ui {
 
-bool ViewClient::OnTouchEvent(const MotionEventAndroid& event,
-                              bool for_touch_handle) {
+bool ViewClient::OnTouchEvent(const MotionEventAndroid& event) {
   return false;
 }
 
diff --git a/ui/android/view_client.h b/ui/android/view_client.h
index 95bbc28..6a01dff1 100644
--- a/ui/android/view_client.h
+++ b/ui/android/view_client.h
@@ -19,8 +19,7 @@
 // the processing.
 class UI_ANDROID_EXPORT ViewClient {
  public:
-  virtual bool OnTouchEvent(const MotionEventAndroid& event,
-                            bool for_touch_handle);
+  virtual bool OnTouchEvent(const MotionEventAndroid& event);
   virtual bool OnMouseEvent(const MotionEventAndroid& event);
   virtual bool OnMouseWheelEvent(const MotionEventAndroid& event);
   virtual bool OnDragEvent(const DragEventAndroid& event);
diff --git a/ui/app_list/presenter/app_list.cc b/ui/app_list/presenter/app_list.cc
index da75f91..be14bb0 100644
--- a/ui/app_list/presenter/app_list.cc
+++ b/ui/app_list/presenter/app_list.cc
@@ -28,14 +28,18 @@
 }
 
 void AppList::UpdateYPositionAndOpacity(int y_position_in_screen,
-                                        float background_opacity,
-                                        bool is_end_gesture) {
+                                        float background_opacity) {
   if (presenter_) {
     presenter_->UpdateYPositionAndOpacity(y_position_in_screen,
-                                          background_opacity, is_end_gesture);
+                                          background_opacity);
   }
 }
 
+void AppList::EndDragFromShelf(mojom::AppListState app_list_state) {
+  if (presenter_)
+    presenter_->EndDragFromShelf(app_list_state);
+}
+
 void AppList::Dismiss() {
   if (presenter_)
     presenter_->Dismiss();
diff --git a/ui/app_list/presenter/app_list.h b/ui/app_list/presenter/app_list.h
index 03feb3e..311442c4 100644
--- a/ui/app_list/presenter/app_list.h
+++ b/ui/app_list/presenter/app_list.h
@@ -28,9 +28,8 @@
   // Helper functions to call the underlying functionality on the presenter.
   void Show(int64_t display_id);
   void UpdateYPositionAndOpacity(int y_position_in_screen,
-                                 float background_opacity,
-                                 bool is_end_gesture);
-
+                                 float background_opacity);
+  void EndDragFromShelf(mojom::AppListState app_list_state);
   void Dismiss();
   void ToggleAppList(int64_t display_id);
   void StartVoiceInteractionSession();
diff --git a/ui/app_list/presenter/app_list_presenter.mojom b/ui/app_list/presenter/app_list_presenter.mojom
index cba536e9..46481e93 100644
--- a/ui/app_list/presenter/app_list_presenter.mojom
+++ b/ui/app_list/presenter/app_list_presenter.mojom
@@ -10,6 +10,24 @@
 // TODO(msw): Ash should implement the app list and presenter; chrome should
 //            just push data about its apps into the app list interface.
 
+// Matches app_list::AppListView:AppListState.
+enum AppListState {
+  // Closes |app_list_main_view_| and dismisses the delegate.
+  CLOSED = 0,
+  // The initial state for the app list when neither maximize or side shelf
+  // modes are active. If set, the widget will peek over the shelf by
+  // kPeekingAppListHeight DIPs.
+  PEEKING = 1,
+  // Entered when text is entered into the search box from peeking mode.
+  HALF = 2,
+  // Default app list state in maximize and side shelf modes. Entered from an
+  // upward swipe from |PEEKING| or from clicking the chevron.
+  FULLSCREEN_ALL_APPS = 3,
+  // Entered from an upward swipe from |HALF| or by entering text in the
+  // search box from |FULLSCREEN_ALL_APPS|.
+  FULLSCREEN_SEARCH = 4,
+};
+
 // Implemented by ash. Used by chrome to set the presenter interface.
 interface AppList {
   // Set the app list presenter interface, to let ash trigger Chrome's app list.
@@ -40,10 +58,10 @@
   // Starts or stops a voice interaction session based on the current state.
   ToggleVoiceInteractionSession();
 
-  // Updates y position and opacity of app list. |is_end_gesture| means it is
-  // the end of the gesture dragging of app list from shelf and should restore
-  // the opacity of the app list.
+  // Updates y position and opacity of app list.
   UpdateYPositionAndOpacity(int32 y_position_in_screen,
-                            float background_opacity,
-                            bool is_end_gesture);
+                            float background_opacity);
+
+  // Ends the drag of app list from shelf.
+  EndDragFromShelf(AppListState app_list_state);
 };
diff --git a/ui/app_list/presenter/app_list_presenter_impl.cc b/ui/app_list/presenter/app_list_presenter_impl.cc
index 4434b394..91afc03 100644
--- a/ui/app_list/presenter/app_list_presenter_impl.cc
+++ b/ui/app_list/presenter/app_list_presenter_impl.cc
@@ -130,11 +130,17 @@
 }
 
 void AppListPresenterImpl::UpdateYPositionAndOpacity(int y_position_in_screen,
-                                                     float background_opacity,
-                                                     bool is_end_gesture) {
+                                                     float background_opacity) {
+  if (view_)
+    view_->UpdateYPositionAndOpacity(y_position_in_screen, background_opacity);
+}
+
+void AppListPresenterImpl::EndDragFromShelf(
+    mojom::AppListState app_list_state) {
   if (view_) {
-    view_->UpdateYPositionAndOpacity(y_position_in_screen, background_opacity,
-                                     is_end_gesture);
+    view_->SetState(AppListView::AppListState(app_list_state));
+    view_->SetIsInDrag(false);
+    view_->DraggingLayout();
   }
 }
 
diff --git a/ui/app_list/presenter/app_list_presenter_impl.h b/ui/app_list/presenter/app_list_presenter_impl.h
index bbe4f2fa..27aecd5 100644
--- a/ui/app_list/presenter/app_list_presenter_impl.h
+++ b/ui/app_list/presenter/app_list_presenter_impl.h
@@ -72,12 +72,12 @@
   // Sets the app list interface pointer; used to report visibility changes.
   void SetAppList(mojom::AppListPtr app_list);
 
-  // Updates y position and opacity of app list. |is_end_gesture| means it is
-  // the end of the gesture dragging of app list from shelf and should restore
-  // the opacity of the app list.
+  // Updates y position and opacity of app list.
   void UpdateYPositionAndOpacity(int y_position_in_screen,
-                                 float background_opacity,
-                                 bool is_end_gesture);
+                                 float background_opacity);
+
+  // Ends the drag of app list from shelf.
+  void EndDragFromShelf(mojom::AppListState app_list_state);
 
  private:
   friend class test::AppListPresenterImplTestApi;
diff --git a/ui/app_list/presenter/test/test_app_list_presenter.cc b/ui/app_list/presenter/test/test_app_list_presenter.cc
index 36d480c..03da9e5 100644
--- a/ui/app_list/presenter/test/test_app_list_presenter.cc
+++ b/ui/app_list/presenter/test/test_app_list_presenter.cc
@@ -11,9 +11,8 @@
 
 TestAppListPresenter::~TestAppListPresenter() {}
 
-app_list::mojom::AppListPresenterPtr
-TestAppListPresenter::CreateInterfacePtrAndBind() {
-  app_list::mojom::AppListPresenterPtr ptr;
+mojom::AppListPresenterPtr TestAppListPresenter::CreateInterfacePtrAndBind() {
+  mojom::AppListPresenterPtr ptr;
   binding_.Bind(mojo::MakeRequest(&ptr));
   return ptr;
 }
@@ -39,10 +38,14 @@
 }
 
 void TestAppListPresenter::UpdateYPositionAndOpacity(int y_position_in_screen,
-                                                     float background_opacity,
-                                                     bool is_end_gesture) {
+                                                     float background_opacity) {
   set_y_position_count_++;
 }
 
+void TestAppListPresenter::EndDragFromShelf(
+    mojom::AppListState app_list_state) {
+  app_list_state_ = app_list_state;
+}
+
 }  // namespace test
 }  // namespace app_list
diff --git a/ui/app_list/presenter/test/test_app_list_presenter.h b/ui/app_list/presenter/test/test_app_list_presenter.h
index 07b63d8..95ef76d 100644
--- a/ui/app_list/presenter/test/test_app_list_presenter.h
+++ b/ui/app_list/presenter/test/test_app_list_presenter.h
@@ -14,12 +14,12 @@
 
 // A test implementation of AppListPresenter that records function call counts.
 // Registers itself as the presenter for the app list on construction.
-class TestAppListPresenter : public app_list::mojom::AppListPresenter {
+class TestAppListPresenter : public mojom::AppListPresenter {
  public:
   TestAppListPresenter();
   ~TestAppListPresenter() override;
 
-  app_list::mojom::AppListPresenterPtr CreateInterfacePtrAndBind();
+  mojom::AppListPresenterPtr CreateInterfacePtrAndBind();
 
   // app_list::mojom::AppListPresenter:
   void Show(int64_t display_id) override;
@@ -28,8 +28,8 @@
   void StartVoiceInteractionSession() override;
   void ToggleVoiceInteractionSession() override;
   void UpdateYPositionAndOpacity(int y_position_in_screen,
-                                 float background_opacity,
-                                 bool is_end_gesture) override;
+                                 float background_opacity) override;
+  void EndDragFromShelf(mojom::AppListState app_list_state) override;
 
   size_t show_count() const { return show_count_; }
   size_t dismiss_count() const { return dismiss_count_; }
@@ -39,6 +39,7 @@
     return voice_session_toggle_count_;
   }
   size_t set_y_position_count() const { return set_y_position_count_; }
+  mojom::AppListState app_list_state() const { return app_list_state_; }
 
  private:
   size_t show_count_ = 0u;
@@ -47,8 +48,9 @@
   size_t voice_session_count_ = 0u;
   size_t voice_session_toggle_count_ = 0u;
   size_t set_y_position_count_ = 0u;
+  mojom::AppListState app_list_state_ = mojom::AppListState::CLOSED;
 
-  mojo::Binding<app_list::mojom::AppListPresenter> binding_;
+  mojo::Binding<mojom::AppListPresenter> binding_;
 
   DISALLOW_COPY_AND_ASSIGN(TestAppListPresenter);
 };
diff --git a/ui/app_list/views/app_list_view.cc b/ui/app_list/views/app_list_view.cc
index 1464e7de..3a1313a 100644
--- a/ui/app_list/views/app_list_view.cc
+++ b/ui/app_list/views/app_list_view.cc
@@ -608,8 +608,7 @@
                        initial_drag_point_.y() + initial_window_bounds_.y();
 
   UpdateYPositionAndOpacity(new_y_position,
-                            GetAppListBackgroundOpacityDuringDragging(),
-                            false /* is_end_gesture */);
+                            GetAppListBackgroundOpacityDuringDragging());
 }
 
 void AppListView::EndDrag(const gfx::Point& location) {
@@ -1231,21 +1230,16 @@
 }
 
 void AppListView::UpdateYPositionAndOpacity(int y_position_in_screen,
-                                            float background_opacity,
-                                            bool is_end_gesture) {
-  SetIsInDrag(!is_end_gesture);
+                                            float background_opacity) {
+  SetIsInDrag(true);
   background_opacity_ = background_opacity;
-  if (is_end_gesture) {
-    SetState(FULLSCREEN_ALL_APPS);
-  } else {
-    gfx::Rect new_widget_bounds = fullscreen_widget_->GetWindowBoundsInScreen();
-    app_list_y_position_in_screen_ =
-        std::max(y_position_in_screen, GetDisplayNearestView().bounds().y());
-    new_widget_bounds.set_y(app_list_y_position_in_screen_);
-    gfx::NativeView native_view = fullscreen_widget_->GetNativeView();
-    ::wm::ConvertRectFromScreen(native_view->parent(), &new_widget_bounds);
-    native_view->SetBounds(new_widget_bounds);
-  }
+  gfx::Rect new_widget_bounds = fullscreen_widget_->GetWindowBoundsInScreen();
+  app_list_y_position_in_screen_ =
+      std::max(y_position_in_screen, GetDisplayNearestView().bounds().y());
+  new_widget_bounds.set_y(app_list_y_position_in_screen_);
+  gfx::NativeView native_view = fullscreen_widget_->GetNativeView();
+  ::wm::ConvertRectFromScreen(native_view->parent(), &new_widget_bounds);
+  native_view->SetBounds(new_widget_bounds);
 
   DraggingLayout();
 }
@@ -1278,6 +1272,19 @@
   return fullscreen_widget_->GetWorkAreaBoundsInScreen().bottom();
 }
 
+void AppListView::DraggingLayout() {
+  float shield_opacity =
+      is_background_blur_enabled_ ? kAppListOpacityWithBlur : kAppListOpacity;
+  app_list_background_shield_->layer()->SetOpacity(
+      is_in_drag_ ? background_opacity_ : shield_opacity);
+
+  // Updates the opacity of the items in the app list.
+  search_box_view_->UpdateOpacity();
+  GetAppsGridView()->UpdateOpacity();
+
+  Layout();
+}
+
 void AppListView::OnSpeechRecognitionStateChanged(
     SpeechRecognitionState new_state) {
   if (!speech_view_)
@@ -1361,19 +1368,6 @@
   SetState(app_list_state_);
 }
 
-void AppListView::DraggingLayout() {
-  float shield_opacity =
-      is_background_blur_enabled_ ? kAppListOpacityWithBlur : kAppListOpacity;
-  app_list_background_shield_->layer()->SetOpacity(
-      is_in_drag_ ? background_opacity_ : shield_opacity);
-
-  // Updates the opacity of the items in the app list.
-  search_box_view_->UpdateOpacity();
-  GetAppsGridView()->UpdateOpacity();
-
-  Layout();
-}
-
 float AppListView::GetAppListBackgroundOpacityDuringDragging() {
   float top_of_applist = fullscreen_widget_->GetWindowBoundsInScreen().y();
   float dragging_height = std::max((GetWorkAreaBottom() - top_of_applist), 0.f);
diff --git a/ui/app_list/views/app_list_view.h b/ui/app_list/views/app_list_view.h
index 2534b91..4b336f6 100644
--- a/ui/app_list/views/app_list_view.h
+++ b/ui/app_list/views/app_list_view.h
@@ -163,12 +163,9 @@
   // whether the search box is empty.
   void SetStateFromSearchBoxView(bool search_box_is_empty);
 
-  // Updates y position and opacity of app list. |is_end_gesture| means it is
-  // the end of the gesture dragging of app list from shelf and should restore
-  // the opacity of the app list.
+  // Updates y position and opacity of app list.
   void UpdateYPositionAndOpacity(int y_position_in_screen,
-                                 float background_opacity,
-                                 bool is_end_gesture);
+                                 float background_opacity);
 
   // Gets the PaginationModel owned by this view's apps grid.
   PaginationModel* GetAppsPaginationModel() const;
@@ -183,6 +180,9 @@
   // Gets current work area bottom.
   int GetWorkAreaBottom();
 
+  // Layouts the app list during dragging.
+  void DraggingLayout();
+
   views::Widget* get_fullscreen_widget_for_test() const {
     return fullscreen_widget_;
   }
@@ -286,9 +286,6 @@
   void OnDisplayMetricsChanged(const display::Display& display,
                                uint32_t changed_metrics) override;
 
-  // Layouts the app list during dragging.
-  void DraggingLayout();
-
   // Gets app list background opacity during dragging.
   float GetAppListBackgroundOpacityDuringDragging();
 
diff --git a/ui/app_list/views/apps_grid_view.cc b/ui/app_list/views/apps_grid_view.cc
index 5a4ab22..985c29d 100644
--- a/ui/app_list/views/apps_grid_view.cc
+++ b/ui/app_list/views/apps_grid_view.cc
@@ -64,8 +64,8 @@
 // Padding space in pixels between pages.
 constexpr int kPagePadding = 40;
 
-// Extra page padding which ensures that the page break space for apps are 48px.
-constexpr int kExtraPagePdding = 36;
+// Padding space in pixels between pages for fullscreen launcher.
+constexpr int kPagePaddingFullscreen = 48;
 
 // Preferred tile size when showing in fixed layout.
 constexpr int kPreferredTileWidth = 100;
@@ -1454,7 +1454,7 @@
       }
     }
   } else {
-    const int page_height = grid_size.height();
+    const int page_height = grid_size.height() + kPagePaddingFullscreen;
     if (page_of_view < current_page)
       y_offset = -page_height;
     else if (page_of_view > current_page)
@@ -1491,26 +1491,21 @@
     const int col = view_index.slot % cols_;
     gfx::Rect tile_slot = GetExpectedTileBounds(row, col);
     gfx::Vector2d offset = CalculateTransitionOffset(view_index.page);
-    const PaginationModel::Transition& transition =
-        pagination_model_.transition();
-    if (is_fullscreen_app_list_enabled_ && transition.progress > 0) {
+    if (is_fullscreen_app_list_enabled_) {
+      // For |current_page|'s neighbor pages, do adjustments to ensure page
+      // break space.
       const int current_page = pagination_model_.selected_page();
-      const bool forward = transition.target_page > current_page ? true : false;
-      // When transiting to previous page, ensure 48px page break space from
-      // just previous page since only the previous page could be visiable;
-      // and vice versa.
-      if (!forward && view_index.page == current_page - 1) {
+      if (view_index.page == current_page - 1) {
         if (view_index.page == 0) {
           offset.set_y(offset.y() + GetHeightOnTopOfAllAppsTiles(0) -
-                       GetHeightOnTopOfAllAppsTiles(1) -
-                       2 * kTileVerticalPadding - kExtraPagePdding);
+                       GetHeightOnTopOfAllAppsTiles(1));
         } else {
-          offset.set_y(offset.y() + GetHeightOnTopOfAllAppsTiles(current_page) -
-                       kExtraPagePdding);
+          offset.set_y(offset.y() + GetHeightOnTopOfAllAppsTiles(current_page) +
+                       2 * kTileVerticalPadding);
         }
-      } else if (forward && view_index.page == current_page + 1) {
-        offset.set_y(offset.y() - GetHeightOnTopOfAllAppsTiles(current_page) +
-                     kExtraPagePdding);
+      } else if (view_index.page == current_page + 1) {
+        offset.set_y(offset.y() - GetHeightOnTopOfAllAppsTiles(current_page) -
+                     2 * kTileVerticalPadding);
       }
     }
     tile_slot.Offset(offset.x(), offset.y());
@@ -1871,8 +1866,11 @@
 void AppsGridView::UpdateOpacity() {
   int app_list_y_position_in_screen =
       contents_view_->app_list_view()->app_list_y_position_in_screen();
-  int work_area_bottom = contents_view_->app_list_view()->GetWorkAreaBottom();
-  bool is_in_drag = contents_view_->app_list_view()->is_in_drag();
+  AppListView* app_list_view = contents_view_->app_list_view();
+  int work_area_bottom = app_list_view->GetWorkAreaBottom();
+  bool should_restore_opacity =
+      !app_list_view->is_in_drag() &&
+      (app_list_view->app_list_state() != AppListView::AppListState::CLOSED);
 
   // The opacity of suggested apps is a function of the fractional displacement
   // of the app list from collapsed(0) to peeking(1) state. When the fraction
@@ -1888,7 +1886,8 @@
                              kSuggestedAppsOpacityStartFraction),
                         0.f),
                1.0f);
-  suggestions_container_->layer()->SetOpacity(is_in_drag ? opacity : 1.0f);
+  suggestions_container_->layer()->SetOpacity(should_restore_opacity ? 1.0f
+                                                                     : opacity);
 
   // The opacity of expand arrow during dragging from collapsed(0) to peeking(1)
   // state. When the dragging amount fraction changes from
@@ -1918,7 +1917,8 @@
                                    kAllAppsIndicatorOpacityStartFraction),
                               0.f),
                      1.0f);
-  all_apps_indicator_->layer()->SetOpacity(is_in_drag ? opacity : 1.0f);
+  all_apps_indicator_->layer()->SetOpacity(should_restore_opacity ? 1.0f
+                                                                  : opacity);
 
   // The opacity of expand arrow during dragging from peeking(0) to
   // fullscreen(1) state. When the dragging amount fraction changes from
@@ -1934,10 +1934,10 @@
   if (app_list_y_position_in_screen <
       (work_area_bottom + kShelfSize - kPeekingAppListHeight)) {
     expand_arrow_view_->layer()->SetOpacity(
-        is_in_drag ? arrow_fullscreen_opacity : 1.0f);
+        should_restore_opacity ? 1.0f : arrow_fullscreen_opacity);
   } else {
-    expand_arrow_view_->layer()->SetOpacity(is_in_drag ? arrow_peeking_opacity
-                                                       : 1.0f);
+    expand_arrow_view_->layer()->SetOpacity(
+        should_restore_opacity ? 1.0f : arrow_peeking_opacity);
   }
 
   // Updates the opacity of all apps. The opacity of the app starting at 0.f
@@ -1977,7 +1977,7 @@
       opacity = std::max(opacity * opacity_factor, 0.f);
     }
 
-    item_view->layer()->SetOpacity(is_in_drag ? opacity : 1.0f);
+    item_view->layer()->SetOpacity(should_restore_opacity ? 1.0f : opacity);
   }
 
   // Updates the opacity of page switcher buttons. The same rule as all apps.
@@ -1990,7 +1990,8 @@
                      (kAllAppsOpacityEndPx - kAllAppsOpacityStartPx),
                  0.f),
         1.0f);
-    page_switcher_view_->layer()->SetOpacity(is_in_drag ? opacity : 1.0f);
+    page_switcher_view_->layer()->SetOpacity(should_restore_opacity ? 1.0f
+                                                                    : opacity);
   }
 }
 
diff --git a/ui/app_list/views/search_box_view.cc b/ui/app_list/views/search_box_view.cc
index e5743b8..3b73ebb9 100644
--- a/ui/app_list/views/search_box_view.cc
+++ b/ui/app_list/views/search_box_view.cc
@@ -712,17 +712,20 @@
                              app_list_y_position_in_screen) /
       (kPeekingAppListHeight - kShelfSize);
 
-  float opacity = 1.0f;
-  if (contents_view->app_list_view()->is_in_drag())
-    opacity =
-        std::min(std::max((fraction - kOpacityStartFraction) /
-                              (kOpacityEndFraction - kOpacityStartFraction),
-                          0.f),
-                 1.0f);
+  float opacity =
+      std::min(std::max((fraction - kOpacityStartFraction) /
+                            (kOpacityEndFraction - kOpacityStartFraction),
+                        0.f),
+               1.0f);
 
+  AppListView* app_list_view = contents_view->app_list_view();
+  bool should_restore_opacity =
+      !app_list_view->is_in_drag() &&
+      (app_list_view->app_list_state() != AppListView::AppListState::CLOSED);
   // Restores the opacity of searchbox if the gesture dragging ends.
-  this->layer()->SetOpacity(opacity);
-  contents_view->search_results_page_view()->layer()->SetOpacity(opacity);
+  this->layer()->SetOpacity(should_restore_opacity ? 1.0f : opacity);
+  contents_view->search_results_page_view()->layer()->SetOpacity(
+      should_restore_opacity ? 1.0f : opacity);
 }
 
 bool SearchBoxView::IsArrowKey(const ui::KeyEvent& event) {
diff --git a/ui/aura/mus/hit_test_data_provider_aura.cc b/ui/aura/mus/hit_test_data_provider_aura.cc
index d715f7e..683502c6 100644
--- a/ui/aura/mus/hit_test_data_provider_aura.cc
+++ b/ui/aura/mus/hit_test_data_provider_aura.cc
@@ -21,8 +21,12 @@
   auto hit_test_region = viz::mojom::HitTestRegion::New();
   DCHECK(window_port->GetFrameSinkId().is_valid());
   hit_test_region->frame_sink_id = window_port->GetFrameSinkId();
-  if (layer->GetPrimarySurfaceInfo())
-    hit_test_region->surface_id = layer->GetPrimarySurfaceInfo()->id();
+  if (layer->GetPrimarySurfaceInfo()) {
+    DCHECK(window_port->GetFrameSinkId() ==
+           layer->GetPrimarySurfaceInfo()->id().frame_sink_id());
+    hit_test_region->local_surface_id =
+        layer->GetPrimarySurfaceInfo()->id().local_surface_id();
+  }
   hit_test_region->flags = flags;
   hit_test_region->rect = rect;
   hit_test_region->transform = layer->transform();
diff --git a/ui/aura/mus/hit_test_data_provider_aura_unittest.cc b/ui/aura/mus/hit_test_data_provider_aura_unittest.cc
index 8b6368e..2cc0f9d 100644
--- a/ui/aura/mus/hit_test_data_provider_aura_unittest.cc
+++ b/ui/aura/mus/hit_test_data_provider_aura_unittest.cc
@@ -132,6 +132,9 @@
   DISALLOW_COPY_AND_ASSIGN(HitTestDataProviderAuraTest);
 };
 
+// TODO(riajiang): Add test cases for kHitTestChildSurface to ensure
+// that local_surface_id is set and used correctly.
+
 // Tests that the order of reported hit-test regions matches windows Z-order.
 TEST_F(HitTestDataProviderAuraTest, Stacking) {
   const auto hit_test_data_1 = hit_test_data_provider()->GetHitTestData();
@@ -144,8 +147,6 @@
                                  viz::mojom::kHitTestTouch);
     EXPECT_EQ(region->frame_sink_id,
               WindowPortMus::Get(expected_order_1[i])->GetFrameSinkId());
-    EXPECT_EQ(region->surface_id.local_surface_id(),
-              WindowMus::Get(expected_order_1[i])->GetLocalSurfaceId());
     EXPECT_EQ(region->rect.ToString(),
               expected_order_1[i]->bounds().ToString());
     i++;
@@ -163,8 +164,6 @@
                                  viz::mojom::kHitTestTouch);
     EXPECT_EQ(region->frame_sink_id,
               WindowPortMus::Get(expected_order_2[i])->GetFrameSinkId());
-    EXPECT_EQ(region->surface_id.local_surface_id(),
-              WindowMus::Get(expected_order_2[i])->GetLocalSurfaceId());
     EXPECT_EQ(region->rect.ToString(),
               expected_order_2[i]->bounds().ToString());
     i++;
@@ -195,8 +194,6 @@
   for (const auto& region : hit_test_data->regions) {
     EXPECT_EQ(region->frame_sink_id,
               WindowPortMus::Get(expected_windows[i])->GetFrameSinkId());
-    EXPECT_EQ(region->surface_id.local_surface_id(),
-              WindowMus::Get(expected_windows[i])->GetLocalSurfaceId());
     EXPECT_EQ(region->flags, expected_flags[i]);
     gfx::Rect expected_bounds = expected_windows[i]->bounds();
     expected_bounds.Inset(gfx::Insets(expected_insets[i]));
@@ -235,8 +232,6 @@
   for (const auto& region : hit_test_data->regions) {
     EXPECT_EQ(region->frame_sink_id,
               WindowPortMus::Get(expected_windows[i])->GetFrameSinkId());
-    EXPECT_EQ(region->surface_id.local_surface_id(),
-              WindowMus::Get(expected_windows[i])->GetLocalSurfaceId());
     EXPECT_EQ(region->flags, expected_flags);
     EXPECT_EQ(region->rect.ToString(), expected_bounds[i].ToString());
     i++;
diff --git a/ui/aura/mus/window_tree_client.cc b/ui/aura/mus/window_tree_client.cc
index 222600d..d3eef525 100644
--- a/ui/aura/mus/window_tree_client.cc
+++ b/ui/aura/mus/window_tree_client.cc
@@ -657,21 +657,6 @@
   delegate_->OnEmbed(std::move(window_tree_host));
 }
 
-void WindowTreeClient::OnSetDisplayRootDone(
-    Id window_id,
-    const base::Optional<viz::LocalSurfaceId>& local_surface_id) {
-  // The only way SetDisplayRoot() should fail is if we've done something wrong.
-  CHECK(local_surface_id.has_value());
-  WindowMus* window = GetWindowByServerId(window_id);
-  if (!window)
-    return;  // Display was already deleted.
-
-  // TODO(sky): figure out why this has to be here rather than in
-  // WindowTreeHostMus's constructor.
-  ui::Compositor* compositor = window->GetWindow()->GetHost()->compositor();
-  compositor->SetLocalSurfaceId(*local_surface_id);
-}
-
 WindowTreeHostMus* WindowTreeClient::WmNewDisplayAddedImpl(
     const display::Display& display,
     ui::mojom::WindowDataPtr root_data,
@@ -827,8 +812,7 @@
       window_manager_client_->SetDisplayRoot(
           display, display_init_params->viewport_metrics.Clone(),
           display_init_params->is_primary_display, window->server_id(),
-          base::Bind(&WindowTreeClient::OnSetDisplayRootDone,
-                     base::Unretained(this), window->server_id()));
+          base::Bind(&OnAckMustSucceed));
     }
   }
 }
@@ -2083,9 +2067,10 @@
     WindowMus* display_root_window = WindowMus::Get(window_tree_host->window());
     window_manager_client_->SetDisplayRoot(
         display, std::move(viewport_metrics), is_primary_display,
-        display_root_window->server_id(),
-        base::Bind(&WindowTreeClient::OnSetDisplayRootDone,
-                   base::Unretained(this), display_root_window->server_id()));
+        display_root_window->server_id(), base::Bind(&OnAckMustSucceed));
+    window_tree_host->compositor()->SetLocalSurfaceId(
+        display_root_window->GetOrAllocateLocalSurfaceId(
+            window_tree_host->GetBoundsInPixels().size()));
   }
 }
 
diff --git a/ui/aura/mus/window_tree_client.h b/ui/aura/mus/window_tree_client.h
index e5747f3f..421bfa5 100644
--- a/ui/aura/mus/window_tree_client.h
+++ b/ui/aura/mus/window_tree_client.h
@@ -288,11 +288,6 @@
                    bool drawn,
                    const base::Optional<viz::LocalSurfaceId>& local_surface_id);
 
-  // Called once mus acks the call to SetDisplayRoot().
-  void OnSetDisplayRootDone(
-      Id window_id,
-      const base::Optional<viz::LocalSurfaceId>& local_surface_id);
-
   // Called by WmNewDisplayAdded().
   WindowTreeHostMus* WmNewDisplayAddedImpl(
       const display::Display& display,
diff --git a/ui/aura/mus/window_tree_host_mus.cc b/ui/aura/mus/window_tree_host_mus.cc
index 6ee2094..92725884 100644
--- a/ui/aura/mus/window_tree_host_mus.cc
+++ b/ui/aura/mus/window_tree_host_mus.cc
@@ -87,6 +87,12 @@
 
   // Mus windows are assumed hidden.
   compositor()->SetVisible(false);
+
+  if (window_mus->window_mus_type() ==
+      WindowMusType::DISPLAY_MANUALLY_CREATED) {
+    compositor()->SetLocalSurfaceId(
+        window_mus->GetOrAllocateLocalSurfaceId(bounds_in_pixels.size()));
+  }
 }
 
 WindowTreeHostMus::~WindowTreeHostMus() {
diff --git a/ui/events/android/motion_event_android.cc b/ui/events/android/motion_event_android.cc
index 4d458420..09f030db 100644
--- a/ui/events/android/motion_event_android.cc
+++ b/ui/events/android/motion_event_android.cc
@@ -209,6 +209,7 @@
                                        jint android_meta_state,
                                        jfloat raw_offset_x_pixels,
                                        jfloat raw_offset_y_pixels,
+                                       jboolean for_touch_handle,
                                        const Pointer* const pointer0,
                                        const Pointer* const pointer1)
     : pix_to_dip_(pix_to_dip),
@@ -216,6 +217,7 @@
       ticks_y_(ticks_y),
       tick_multiplier_(tick_multiplier),
       time_sec_(time_ms / 1000),
+      for_touch_handle_(for_touch_handle),
       cached_time_(FromAndroidTime(time_ms)),
       cached_action_(FromAndroidAction(android_action)),
       cached_pointer_count_(pointer_count),
@@ -246,6 +248,7 @@
       ticks_y_(e.ticks_y_),
       tick_multiplier_(e.tick_multiplier_),
       time_sec_(e.time_sec_),
+      for_touch_handle_(e.for_touch_handle_),
       cached_time_(e.cached_time_),
       cached_action_(e.cached_action_),
       cached_pointer_count_(e.cached_pointer_count_),
@@ -261,6 +264,22 @@
     cached_pointers_[1] = e.cached_pointers_[1];
 }
 
+//  static
+int MotionEventAndroid::GetAndroidActionForTesting(int action) {
+  int android_action = JNI_MotionEvent::ACTION_CANCEL;
+  switch (action) {
+    case ui::MotionEvent::ACTION_DOWN:
+      android_action = JNI_MotionEvent::ACTION_DOWN;
+      break;
+    case ui::MotionEvent::ACTION_UP:
+      android_action = JNI_MotionEvent::ACTION_UP;
+      break;
+    default:
+      NOTIMPLEMENTED() << "Conversion not supported: " << action;
+  }
+  return android_action;
+}
+
 std::unique_ptr<MotionEventAndroid> MotionEventAndroid::CreateFor(
     const gfx::PointF& point) const {
   std::unique_ptr<MotionEventAndroid> event(new MotionEventAndroid(*this));
diff --git a/ui/events/android/motion_event_android.h b/ui/events/android/motion_event_android.h
index a208366a..e23d0e5 100644
--- a/ui/events/android/motion_event_android.h
+++ b/ui/events/android/motion_event_android.h
@@ -25,6 +25,10 @@
 // while all *output* coordinates are in DIPs (as with WebTouchEvent).
 class EVENTS_EXPORT MotionEventAndroid : public MotionEvent {
  public:
+  // Returns the motion event action defined in Java layer for a given
+  // MotionEvent::Action.
+  static int GetAndroidActionForTesting(int action);
+
   struct Pointer {
     Pointer(jint id,
             jfloat pos_x_pixels,
@@ -64,6 +68,7 @@
                      jint meta_state,
                      jfloat raw_offset_x_pixels,
                      jfloat raw_offset_y_pixels,
+                     jboolean for_touch_handle,
                      const Pointer* const pointer0,
                      const Pointer* const pointer1);
   ~MotionEventAndroid() override;
@@ -110,6 +115,7 @@
   float ticks_y() const { return ticks_y_; }
   float time_sec() const { return time_sec_; }
   float GetTickMultiplier() const;
+  bool for_touch_handle() const { return for_touch_handle_; }
 
   base::android::ScopedJavaLocalRef<jobject> GetJavaObject() const;
 
@@ -139,6 +145,8 @@
   const float tick_multiplier_;
   const uint64_t time_sec_;
 
+  const bool for_touch_handle_;
+
   const base::TimeTicks cached_time_;
   const Action cached_action_;
   const size_t cached_pointer_count_;
diff --git a/ui/events/android/motion_event_android_unittest.cc b/ui/events/android/motion_event_android_unittest.cc
index 8c67a9d..e71b5790 100644
--- a/ui/events/android/motion_event_android_unittest.cc
+++ b/ui/events/android/motion_event_android_unittest.cc
@@ -66,7 +66,7 @@
       base::android::AttachCurrentThread(), nullptr, kPixToDip, 0.f, 0.f, 0.f,
       event_time_ms, kAndroidActionDown, pointer_count, history_size,
       action_index, kAndroidActionButton, kAndroidButtonPrimary,
-      kAndroidAltKeyDown, raw_offset, -raw_offset, &p0, &p1);
+      kAndroidAltKeyDown, raw_offset, -raw_offset, false, &p0, &p1);
 
   EXPECT_EQ(MotionEvent::ACTION_DOWN, event.GetAction());
   EXPECT_EQ(event_time, event.GetEventTime());
@@ -106,7 +106,8 @@
       1, 13.7f, -7.13f, 5.3f, 1.2f, 0.1f, 0.2f, kAndroidToolTypeFinger);
   MotionEventAndroid event(base::android::AttachCurrentThread(), nullptr,
                            kPixToDip, 0, 0, 0, 0, kAndroidActionDown,
-                           pointer_count, 0, 0, 0, 0, 0, 0, 0, &p0, nullptr);
+                           pointer_count, 0, 0, 0, 0, 0, 0, 0, false, &p0,
+                           nullptr);
 
   std::unique_ptr<MotionEvent> clone = event.Clone();
   EXPECT_EQ(ui::test::ToString(event), ui::test::ToString(*clone));
@@ -120,7 +121,7 @@
   MotionEventAndroid event(base::android::AttachCurrentThread(), nullptr,
                            kPixToDip, 0, 0, 0, event_time_ms,
                            kAndroidActionDown, pointer_count, 0, 0, 0, 0, 0, 0,
-                           0, &p0, nullptr);
+                           0, false, &p0, nullptr);
 
   std::unique_ptr<MotionEvent> cancel_event = event.Cancel();
   EXPECT_EQ(MotionEvent::ACTION_CANCEL, cancel_event->GetAction());
@@ -142,7 +143,7 @@
   MotionEventAndroid::Pointer p1(1, 0, 0, 0, 0, orientation1, 0, 0);
   MotionEventAndroid event(base::android::AttachCurrentThread(), nullptr,
                            kPixToDip, 0, 0, 0, 0, kAndroidActionDown,
-                           pointer_count, 0, 0, 0, 0, 0, 0, 0, &p0, &p1);
+                           pointer_count, 0, 0, 0, 0, 0, 0, 0, false, &p0, &p1);
 
   EXPECT_EQ(0.f, event.GetOrientation(0));
   EXPECT_EQ(0.f, event.GetOrientation(1));
@@ -154,8 +155,8 @@
   MotionEventAndroid::Pointer p0(0, 0, 0, 0, 0, 0, 0, 0);
   MotionEventAndroid event(base::android::AttachCurrentThread(), nullptr,
                            kPixToDip, 0, 0, 0, 0, kAndroidActionDown,
-                           pointer_count, history_size, 0, 0, 0, 0, 0, 0, &p0,
-                           nullptr);
+                           pointer_count, history_size, 0, 0, 0, 0, 0, 0, false,
+                           &p0, nullptr);
 
   EXPECT_EQ(0U, event.GetHistorySize());
 }
@@ -171,7 +172,7 @@
   MotionEventAndroid event(base::android::AttachCurrentThread(), nullptr,
                            kPixToDip, 0, 0, 0, 0, kAndroidActionPointerDown,
                            pointer_count, history_size, action_index, 0, 0, 0,
-                           0, 0, &p0, &p1);
+                           0, 0, false, &p0, &p1);
 
   EXPECT_EQ(MotionEvent::ACTION_POINTER_DOWN, event.GetAction());
   EXPECT_EQ(action_index, event.GetActionIndex());
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_tap_handler.js b/ui/file_manager/file_manager/foreground/js/ui/file_tap_handler.js
index 035d75f..b23a548 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_tap_handler.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_tap_handler.js
@@ -140,6 +140,8 @@
       this.activeTouchId_ = touch.identifier;
       this.startTouchX_ = this.lastTouchX_ = touch.clientX;
       this.startTouchY_ = this.lastTouchY_ = touch.clientY;
+      this.totalMoveX_ = 0;
+      this.totalMoveY_ = 0;
 
       this.tapStarted_ = true;
       this.activeItemIndex_ = index;
@@ -186,14 +188,17 @@
       break;
 
     case 'touchend':
-      // Mark as no longer being touched
+      if (!this.tapStarted_)
+        break;
+      // Mark as no longer being touched.
+      // Two-finger tap event is issued when either of the 2 touch points is
+      // released. Stop tracking the tap to avoid issuing duplicate events.
+      this.tapStarted_ = false;
       this.activeTouchId_ = undefined;
       if (this.longTapDetectorTimerId_ != -1) {
         clearTimeout(this.longTapDetectorTimerId_);
         this.longTapDetectorTimerId_ = -1;
       }
-      if (!this.tapStarted_)
-        break;
       if (this.isLongTap_) {
         // The item at the touch start position is treated as the target item,
         // rather than the one at the touch end position. Note that |index| is
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_tap_handler_unittest.html b/ui/file_manager/file_manager/foreground/js/ui/file_tap_handler_unittest.html
new file mode 100644
index 0000000..146270b8
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_tap_handler_unittest.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<!-- 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.
+  -->
+
+<script src="../../../../../../ui/webui/resources/js/assert.js"></script>
+
+<script src="../../../common/js/unittest_util.js"></script>
+<script src="../../../common/js/util.js"></script>
+
+<script src="file_tap_handler.js"></script>
+<script src="file_tap_handler_unittest.js"></script>
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_tap_handler_unittest.js b/ui/file_manager/file_manager/foreground/js/ui/file_tap_handler_unittest.js
new file mode 100644
index 0000000..6fa390e
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_tap_handler_unittest.js
@@ -0,0 +1,313 @@
+// 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.
+
+/** @type {!FileTapHandler} handler the handler. */
+var handler;
+
+/**
+ * @type {!Element}
+ */
+var dummyTarget;
+
+/**
+ * @type {!Array<!Object>}
+ */
+var events;
+
+/**
+ * @type {function(!Event, number, !FiletapHandler.TapEvent)}
+ */
+var handleTap = function(e, index, eventType) {
+  events.push({index: index, eventType: eventType});
+  return false;
+};
+
+/**
+ * @param {number} identifier
+ * @param {number} clientX
+ * @param {number} clientY
+ */
+function createTouch(identifier, clientX, clientY) {
+  return new Touch({
+    identifier: identifier,
+    clientX: clientX,
+    clientY: clientY,
+    target: dummyTarget
+  });
+}
+
+function setUp() {
+  handler = new FileTapHandler();
+  dummyTarget = document.body;
+  events = [];
+}
+
+function testTap() {
+  var touch = createTouch(0, 300, 400);
+  handler.handleTouchEvents(
+      new TouchEvent('touchstart', {targetTouches: [touch], touches: [touch]}),
+      0, handleTap);
+  // Callback should be called after touchend.
+  assertEquals(0, events.length);
+  handler.handleTouchEvents(
+      new TouchEvent('touchend', {
+        targetTouches: [],
+        touches: [],
+      }),
+      0, handleTap);
+  assertEquals(1, events.length);
+  assertEquals(FileTapHandler.TapEvent.TAP, events[0].eventType);
+  assertEquals(0, events[0].index);
+}
+
+function testIgnoreSlide() {
+  var touch0 = createTouch(0, 300, 400);
+  var touch1 = createTouch(0, 320, 450);
+  handler.handleTouchEvents(
+      new TouchEvent('touchstart', {
+        targetTouches: [touch0],
+        touches: [touch0],
+        changedTouches: [touch0],
+      }),
+      0, handleTap);
+  handler.handleTouchEvents(
+      new TouchEvent('touchmove', {
+        targetTouches: [touch1],
+        touches: [touch1],
+        changedTouches: [touch1],
+      }),
+      1, handleTap);
+  handler.handleTouchEvents(
+      new TouchEvent(
+          'touchend',
+          {changedTouches: [touch1], targetTouches: [], touches: []}),
+      1, handleTap);
+  assertEquals(0, events.length);
+
+  // Next touch should be accepted.
+  var touch2 = createTouch(0, touch0.clientX + 1, touch0.clientY + 2);
+  handler.handleTouchEvents(
+      new TouchEvent('touchstart', {
+        targetTouches: [touch0],
+        touches: [touch0],
+        changedTouches: [touch0],
+      }),
+      0, handleTap);
+  handler.handleTouchEvents(
+      new TouchEvent('touchmove', {
+        targetTouches: [touch2],
+        touches: [touch2],
+        changedTouches: [touch2],
+      }),
+      1, handleTap);
+  handler.handleTouchEvents(
+      new TouchEvent(
+          'touchend',
+          {changedTouches: [touch2], targetTouches: [], touches: []}),
+      1, handleTap);
+  assertEquals(1, events.length);
+  assertEquals(FileTapHandler.TapEvent.TAP, events[0].eventType);
+}
+
+function testTapMoveTolerance() {
+  var touch0 = createTouch(0, 300, 400);
+  var touch1 = createTouch(0, 300, 405);  // moved slightly
+  var touch2 = createTouch(0, 302, 405);  // moved slightly
+  handler.handleTouchEvents(
+      new TouchEvent('touchstart', {
+        changedTouches: [touch0],
+        targetTouches: [touch0],
+        touches: [touch0],
+      }),
+      0, handleTap);
+  // Emulate touching another item in the list due to the small slide.
+  handler.handleTouchEvents(
+      new TouchEvent('touchmove', {
+        changedTouches: [touch1],
+        targetTouches: [touch1],
+        touches: [touch1],
+      }),
+      1, handleTap);
+  handler.handleTouchEvents(
+      new TouchEvent('touchmove', {
+        changedTouches: [touch2],
+        targetTouches: [touch2],
+        touches: [touch2],
+      }),
+      1, handleTap);
+  handler.handleTouchEvents(
+      new TouchEvent('touchend', {
+        changedTouches: [touch2],
+        targetTouches: [],
+        touches: [],
+      }),
+      1, handleTap);
+  assertEquals(1, events.length);
+  assertEquals(FileTapHandler.TapEvent.TAP, events[0].eventType);
+  assertEquals(0, events[0].index);
+}
+
+function testLongTap(callback) {
+  var touch0 = createTouch(0, 300, 400);
+  var touch1 = createTouch(0, 303, 404);
+  handler.handleTouchEvents(
+      new TouchEvent('touchstart', {
+        changedTouches: [touch0],
+        targetTouches: [touch0],
+        touches: [touch0]
+      }),
+      0, handleTap);
+  assertEquals(0, events.length);
+  reportPromise(
+      new Promise(function(resolve) {
+        setTimeout(resolve, 250);
+      })
+          .then(function() {
+            // Move slightly, but still touching.
+            handler.handleTouchEvents(
+                new TouchEvent('touchmove', {
+                  changedTouches: [touch1],
+                  targetTouches: [touch1],
+                  touches: [touch1]
+                }),
+                0, handleTap);
+            return new Promise(function(resolve) {
+              // Exceeds the threshold (500ms) when added with the one above.
+              setTimeout(resolve, 300);
+            });
+          })
+          .then(function() {
+            assertEquals(1, events.length);
+            assertEquals(
+                FileTapHandler.TapEvent.LONG_PRESS, events[0].eventType)
+            assertEquals(0, events[0].index)
+            handler.handleTouchEvents(
+                new TouchEvent('touchend', {
+                  changedTouches: [touch1],
+                  targetTouches: [],
+                  touches: [],
+                }),
+                1, handleTap);
+            assertEquals(2, events.length);
+            assertEquals(FileTapHandler.TapEvent.LONG_TAP, events[1].eventType)
+            assertEquals(0, events[1].index)
+          }),
+      callback);
+}
+
+function testCancelLongTapBySlide(callback) {
+  var touch0 = createTouch(0, 300, 400);
+  var touch1 = createTouch(0, 330, 450);
+  handler.handleTouchEvents(
+      new TouchEvent('touchstart', {
+        changedTouches: [touch0],
+        targetTouches: [touch0],
+        touches: [touch0]
+      }),
+      0, handleTap);
+  assertEquals(0, events.length);
+  reportPromise(
+      new Promise(function(resolve) {
+        setTimeout(resolve, 250);
+      })
+          .then(function() {
+            handler.handleTouchEvents(
+                new TouchEvent('touchmove', {
+                  changedTouches: [touch1],
+                  targetTouches: [touch1],
+                  touches: [touch1]
+                }),
+                0, handleTap);
+            return new Promise(function(resolve) {
+              // Exceeds the threshold (500ms) when added with the one above.
+              setTimeout(resolve, 300);
+            });
+          })
+          .then(function() {
+            assertEquals(0, events.length);
+          }),
+      callback);
+}
+
+function testTwoFingerTap() {
+  var touch0_0 = createTouch(0, 300, 400);
+  var touch0_1 = createTouch(0, 303, 404);
+  var touch1_0 = createTouch(1, 350, 400);
+  var touch1_1 = createTouch(1, 354, 402);
+  // case 1: Release the second touch point first.
+  handler.handleTouchEvents(
+      new TouchEvent('touchstart', {
+        changedTouches: [touch0_0],
+        targetTouches: [touch0_0],
+        touches: [touch0_0],
+      }),
+      0, handleTap);
+  handler.handleTouchEvents(
+      new TouchEvent('touchstart', {
+        changedTouches: [touch1_0],
+        targetTouches: [touch0_0, touch1_0],
+        touches: [touch0_0, touch1_0],
+      }),
+      1, handleTap);
+  handler.handleTouchEvents(
+      new TouchEvent('touchmove', {
+        changedTouches: [touch1_1],
+        targetTouches: [touch0_0, touch1_1],
+        touches: [touch0_0, touch1_1],
+      }),
+      1, handleTap);
+  handler.handleTouchEvents(
+      new TouchEvent('touchend', {
+        changedTouches: [touch1_1],
+        targetTouches: [touch0_0],
+        touches: [touch0_0]
+      }),
+      1, handleTap);
+  handler.handleTouchEvents(
+      new TouchEvent('touchmove', {
+        changedTouches: [touch0_1],
+        targetTouches: [touch0_1],
+        touches: [touch0_1],
+      }),
+      1, handleTap);
+  handler.handleTouchEvents(
+      new TouchEvent(
+          'touchend',
+          {changedTouches: [touch0_1], targetTouches: [], touches: []}),
+      2, handleTap);
+  assertEquals(1, events.length);
+  assertEquals(FileTapHandler.TapEvent.TWO_FINGER_TAP, events[0].eventType);
+  assertEquals(0, events[0].index);
+
+  // case 2: Release the first touch point first.
+  handler.handleTouchEvents(
+      new TouchEvent('touchstart', {
+        changedTouches: [touch0_0],
+        targetTouches: [touch0_0],
+        touches: [touch0_0],
+      }),
+      10, handleTap);
+  handler.handleTouchEvents(
+      new TouchEvent('touchstart', {
+        changedTouches: [touch1_0],
+        targetTouches: [touch0_0, touch1_0],
+        touches: [touch0_0, touch1_0],
+      }),
+      11, handleTap);
+  handler.handleTouchEvents(
+      new TouchEvent('touchend', {
+        changedTouches: [touch0_0],
+        targetTouches: [touch1_0],
+        touches: [touch1_0]
+      }),
+      11, handleTap);
+  handler.handleTouchEvents(
+      new TouchEvent(
+          'touchend',
+          {changedTouches: [touch1_0], targetTouches: [], touches: []}),
+      10, handleTap);
+  assertEquals(2, events.length);
+  assertEquals(FileTapHandler.TapEvent.TWO_FINGER_TAP, events[1].eventType);
+  assertEquals(10, events[1].index);
+}
diff --git a/ui/file_manager/gallery/gallery.html b/ui/file_manager/gallery/gallery.html
index cb4d3fc..6784dbab 100644
--- a/ui/file_manager/gallery/gallery.html
+++ b/ui/file_manager/gallery/gallery.html
@@ -97,7 +97,7 @@
       <div class="filename-spacer">
         <!-- Change this to use paper-input after ChromeVox supports shadow DOM. -->
         <paper-input-container id="rename-input" no-label-float>
-          <input spellcheck="false"></input>
+          <input spellcheck="false">
         </paper-input-container>
       </div>
       <div class="button-spacer">
diff --git a/ui/login/account_picker/md_user_pod_row.js b/ui/login/account_picker/md_user_pod_row.js
index c51218a..09c88a67e 100644
--- a/ui/login/account_picker/md_user_pod_row.js
+++ b/ui/login/account_picker/md_user_pod_row.js
@@ -2909,8 +2909,8 @@
     // Array of users that are shown (public/supervised/regular).
     users_: [],
 
-    // If we're in Touch View mode.
-    touchViewEnabled_: false,
+    // If we're in tablet mode.
+    tabletModeEnabled_: false,
 
     // If testing mode is enabled.
     testingModeEnabled_: false,
@@ -2957,14 +2957,14 @@
 
     /**
      * Return true if user pod row has only single user pod in it, which should
-     * always be focused except desktop and touch view modes.
+     * always be focused except desktop and tablet modes.
      * @type {boolean}
      */
     get alwaysFocusSinglePod() {
       var isDesktopUserManager = Oobe.getInstance().displayType ==
           DISPLAY_TYPE.DESKTOP_USER_MANAGER;
 
-      return (isDesktopUserManager || this.touchViewEnabled_) ?
+      return (isDesktopUserManager || this.tabletModeEnabled_) ?
           false :
           this.pods.length == 1;
     },
@@ -3519,16 +3519,18 @@
     },
 
     /**
-     * Sets the state of touch view mode.
-     * @param {boolean} isTouchViewEnabled true if the mode is on.
+     * Sets the state of tablet mode.
+     * @param {boolean} isTabletModeEnabled true if the mode is on.
      */
-    setTouchViewState: function(isTouchViewEnabled) {
-      this.touchViewEnabled_ = isTouchViewEnabled;
+    setTabletModeState: function(isTabletModeEnabled) {
+      this.tabletModeEnabled_ = isTabletModeEnabled;
       this.pods.forEach(function(pod, index) {
-        pod.actionBoxAreaElement.classList.toggle('forced', isTouchViewEnabled);
-        if (pod.isPublicSessionPod)
+        pod.actionBoxAreaElement.classList.toggle(
+            'forced', isTabletModeEnabled);
+        if (pod.isPublicSessionPod) {
           pod.querySelector('.button-container')
-              .classList.toggle('forced', isTouchViewEnabled);
+              .classList.toggle('forced', isTabletModeEnabled);
+        }
       });
     },
 
diff --git a/ui/login/account_picker/user_pod_row.js b/ui/login/account_picker/user_pod_row.js
index 2bbe706..eeaf351 100644
--- a/ui/login/account_picker/user_pod_row.js
+++ b/ui/login/account_picker/user_pod_row.js
@@ -2684,8 +2684,8 @@
     // Array of users that are shown (public/supervised/regular).
     users_: [],
 
-    // If we're in Touch View mode.
-    touchViewEnabled_: false,
+    // If we're in tablet mode.
+    tabletModeEnabled_: false,
 
     /** @override */
     decorate: function() {
@@ -2721,15 +2721,16 @@
 
     /**
      * Return true if user pod row has only single user pod in it, which should
-     * always be focused except desktop and touch view modes.
+     * always be focused except desktop and tablet modes.
      * @type {boolean}
      */
     get alwaysFocusSinglePod() {
       var isDesktopUserManager = Oobe.getInstance().displayType ==
           DISPLAY_TYPE.DESKTOP_USER_MANAGER;
 
-      return (isDesktopUserManager || this.touchViewEnabled_) ?
-          false : this.children.length == 1;
+      return (isDesktopUserManager || this.tabletModeEnabled_) ?
+          false :
+          this.children.length == 1;
     },
 
     /**
@@ -3246,13 +3247,14 @@
     },
 
     /**
-     * Sets the state of touch view mode.
-     * @param {boolean} isTouchViewEnabled true if the mode is on.
+     * Sets the state of tablet mode.
+     * @param {boolean} isTabletModeEnabled true if the mode is on.
      */
-    setTouchViewState: function(isTouchViewEnabled) {
-      this.touchViewEnabled_ = isTouchViewEnabled;
+    setTabletModeState: function(isTabletModeEnabled) {
+      this.tabletModeEnabled_ = isTabletModeEnabled;
       this.pods.forEach(function(pod, index) {
-        pod.actionBoxAreaElement.classList.toggle('forced', isTouchViewEnabled);
+        pod.actionBoxAreaElement.classList.toggle(
+            'forced', isTabletModeEnabled);
       });
     },
 
diff --git a/ui/login/md_screen_container.css b/ui/login/md_screen_container.css
index c5edef7e..708b08f 100644
--- a/ui/login/md_screen_container.css
+++ b/ui/login/md_screen_container.css
@@ -80,8 +80,10 @@
 #oobe.auto-enrollment-check #inner-container,
 #oobe.autolaunch #inner-container,
 #oobe.confirm-password #inner-container,
+#oobe:not([md-mode]).connect #inner-container,
 #oobe.debugging #inner-container,
 #oobe.enrollment #inner-container,
+#oobe:not([md-mode]).eula #inner-container,
 #oobe.fatal-error #inner-container,
 #oobe.gaia-signin #inner-container,
 #oobe.hid-detection #inner-container,
@@ -89,6 +91,7 @@
 #oobe.oauth-enrollment #inner-container,
 #oobe.password-changed #inner-container,
 #oobe.ad-password-change #inner-container,
+#oobe:not([md-mode]).reset #inner-container,
 #oobe.supervised-user-creation #inner-container,
 #oobe.supervised-user-creation-dialog #inner-container,
 #oobe.terms-of-service #inner-container,
@@ -120,6 +123,13 @@
   transform: translateY(50px) rotateX(-2.5deg);
 }
 
+#oobe:not([md-mode]) #step-logo {
+  -webkit-margin-start: 17px;
+  display: flex;
+  position: absolute;
+  top: 15px;
+}
+
 #oobe[md-mode] #step-logo {
   display: none;
 }
diff --git a/ui/message_center/views/notification_view_md.cc b/ui/message_center/views/notification_view_md.cc
index 80ebab1..f8ded7a 100644
--- a/ui/message_center/views/notification_view_md.cc
+++ b/ui/message_center/views/notification_view_md.cc
@@ -86,10 +86,16 @@
 
 constexpr int kProgressBarHeight = 4;
 
-constexpr int kMessageViewWidth =
+constexpr int kMessageViewWidthWithIcon =
     message_center::kNotificationWidth - kIconViewSize.width() -
+    kLeftContentPaddingWithIcon.left() - kLeftContentPaddingWithIcon.right() -
     kContentRowPadding.left() - kContentRowPadding.right();
 
+constexpr int kMessageViewWidth =
+    message_center::kNotificationWidth - kLeftContentPadding.left() -
+    kLeftContentPadding.right() - kContentRowPadding.left() -
+    kContentRowPadding.right();
+
 // "Roboto-Regular, 13sp" is specified in the mock.
 constexpr int kTextFontSize = 13;
 
@@ -650,14 +656,6 @@
     message_view_->SetLineLimit(kMaxLinesForMessageView);
     message_view_->SetColors(kDimTextColorMD, kContextTextBackgroundColor);
 
-    // TODO(tetsui): Workaround https://crbug.com/682266 by explicitly setting
-    // the width.
-    // Ideally, we should fix the original bug, but it seems there's no obvious
-    // solution for the bug according to https://crbug.com/678337#c7, we should
-    // ensure that the change won't break any of the users of BoxLayout class.
-    DCHECK(right_content_);
-    message_view_->SizeToFit(kMessageViewWidth);
-
     left_content_->AddChildView(message_view_);
   } else {
     message_view_->SetText(text);
@@ -917,8 +915,18 @@
   if (icon_view_ && icon_view_->visible()) {
     left_content_->SetBorder(
         views::CreateEmptyBorder(kLeftContentPaddingWithIcon));
+
+    // TODO(tetsui): Workaround https://crbug.com/682266 by explicitly setting
+    // the width.
+    // Ideally, we should fix the original bug, but it seems there's no obvious
+    // solution for the bug according to https://crbug.com/678337#c7, we should
+    // ensure that the change won't break any of the users of BoxLayout class.
+    if (message_view_)
+      message_view_->SizeToFit(kMessageViewWidthWithIcon);
   } else {
     left_content_->SetBorder(views::CreateEmptyBorder(kLeftContentPadding));
+    if (message_view_)
+      message_view_->SizeToFit(kMessageViewWidth);
   }
 }
 
diff --git a/ui/ozone/demo/surfaceless_gl_renderer.cc b/ui/ozone/demo/surfaceless_gl_renderer.cc
index a566563..c325619 100644
--- a/ui/ozone/demo/surfaceless_gl_renderer.cc
+++ b/ui/ozone/demo/surfaceless_gl_renderer.cc
@@ -142,10 +142,6 @@
   // Show the entire buffer by setting the crop to a unity square.
   overlay_candidate.crop_rect = gfx::RectF(0, 0, 1, 1);
 
-  // The quad rect is the rectangular bounds of the overlay demonstration
-  // rectangle.
-  overlay_candidate.quad_rect_in_target_space = bounds_rect;
-
   // The clip region is the entire screen.
   overlay_candidate.clip_rect = gfx::Rect(size_);
 
diff --git a/ui/ozone/platform/drm/common/drm_util_unittest.cc b/ui/ozone/platform/drm/common/drm_util_unittest.cc
index c86453d..88835c29 100644
--- a/ui/ozone/platform/drm/common/drm_util_unittest.cc
+++ b/ui/ozone/platform/drm/common/drm_util_unittest.cc
@@ -168,7 +168,6 @@
   input_osc.buffer_size = gfx::Size(100, 50);
   input_osc.display_rect = gfx::RectF(1., 2., 3., 4.);
   input_osc.crop_rect = gfx::RectF(10., 20., 30., 40.);
-  input_osc.quad_rect_in_target_space = gfx::Rect(1, 2, 3, 4);
   input_osc.clip_rect = gfx::Rect(10, 20, 30, 40);
   input_osc.is_clipped = true;
   input_osc.plane_z_order = 42;
diff --git a/ui/ozone/platform/drm/gpu/drm_thread.cc b/ui/ozone/platform/drm/gpu/drm_thread.cc
index a8f8a211..177208b 100644
--- a/ui/ozone/platform/drm/gpu/drm_thread.cc
+++ b/ui/ozone/platform/drm/gpu/drm_thread.cc
@@ -318,12 +318,13 @@
 
 // DrmThread requires a BindingSet instead of a simple Binding because it will
 // be used from multiple threads in multiple processes.
-void DrmThread::AddBinding(ozone::mojom::DeviceCursorRequest request) {
+void DrmThread::AddBindingCursorDevice(
+    ozone::mojom::DeviceCursorRequest request) {
   bindings_.AddBinding(this, std::move(request));
 }
 
-void DrmThread::AddBindingGpu(ozone::mojom::GpuAdapterRequest request) {
-  TRACE_EVENT0("drm", "DrmThread::AddBindingGpu");
+void DrmThread::AddBindingDrmDevice(ozone::mojom::DrmDeviceRequest request) {
+  TRACE_EVENT0("drm", "DrmThread::AddBindingDrmDevice");
   binding_.Bind(std::move(request));
 }
 
diff --git a/ui/ozone/platform/drm/gpu/drm_thread.h b/ui/ozone/platform/drm/gpu/drm_thread.h
index 99231bc..c8e0cdc 100644
--- a/ui/ozone/platform/drm/gpu/drm_thread.h
+++ b/ui/ozone/platform/drm/gpu/drm_thread.h
@@ -21,7 +21,7 @@
 #include "ui/ozone/common/gpu/ozone_gpu_message_params.h"
 #include "ui/ozone/platform/drm/common/display_types.h"
 #include "ui/ozone/public/interfaces/device_cursor.mojom.h"
-#include "ui/ozone/public/interfaces/gpu_adapter.mojom.h"
+#include "ui/ozone/public/interfaces/drm_device.mojom.h"
 #include "ui/ozone/public/swap_completion_callback.h"
 
 namespace base {
@@ -57,7 +57,7 @@
 // thread (such as modesetting) no longer block the GPU main thread.
 class DrmThread : public base::Thread,
                   public ozone::mojom::DeviceCursor,
-                  public ozone::mojom::GpuAdapter {
+                  public ozone::mojom::DrmDevice {
  public:
   DrmThread();
   ~DrmThread() override;
@@ -133,10 +133,10 @@
   void Init() override;
 
   // Mojo support for DeviceCursorRequest.
-  void AddBinding(ozone::mojom::DeviceCursorRequest request);
+  void AddBindingCursorDevice(ozone::mojom::DeviceCursorRequest request);
 
-  // Mojo support for GpuAdapter requests.
-  void AddBindingGpu(ozone::mojom::GpuAdapterRequest request);
+  // Mojo support for DrmDevice requests.
+  void AddBindingDrmDevice(ozone::mojom::DrmDeviceRequest request);
 
  private:
   std::unique_ptr<DrmDeviceManager> device_manager_;
@@ -148,8 +148,8 @@
   // requests from two different client threads.
   mojo::BindingSet<ozone::mojom::DeviceCursor> bindings_;
 
-  // The mojo implementation of GpuAdapter can use a simple binding.
-  mojo::Binding<ozone::mojom::GpuAdapter> binding_;
+  // The mojo implementation of DrmDevice can use a simple binding.
+  mojo::Binding<ozone::mojom::DrmDevice> binding_;
 
   DISALLOW_COPY_AND_ASSIGN(DrmThread);
 };
diff --git a/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc b/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc
index 888999b..c3814f1 100644
--- a/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc
+++ b/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc
@@ -63,18 +63,20 @@
                  widget, scanout_formats));
 }
 
-void DrmThreadProxy::AddBinding(ozone::mojom::DeviceCursorRequest request) {
+void DrmThreadProxy::AddBindingCursorDevice(
+    ozone::mojom::DeviceCursorRequest request) {
   drm_thread_.task_runner()->PostTask(
       FROM_HERE,
-      base::Bind(&DrmThread::AddBinding, base::Unretained(&drm_thread_),
-                 base::Passed(&request)));
+      base::Bind(&DrmThread::AddBindingCursorDevice,
+                 base::Unretained(&drm_thread_), base::Passed(&request)));
 }
 
-void DrmThreadProxy::AddBindingGpu(ozone::mojom::GpuAdapterRequest request) {
+void DrmThreadProxy::AddBindingDrmDevice(
+    ozone::mojom::DrmDeviceRequest request) {
   drm_thread_.task_runner()->PostTask(
       FROM_HERE,
-      base::Bind(&DrmThread::AddBindingGpu, base::Unretained(&drm_thread_),
-                 base::Passed(&request)));
+      base::Bind(&DrmThread::AddBindingDrmDevice,
+                 base::Unretained(&drm_thread_), base::Passed(&request)));
 }
 
 }  // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/drm_thread_proxy.h b/ui/ozone/platform/drm/gpu/drm_thread_proxy.h
index a812c666..af59604 100644
--- a/ui/ozone/platform/drm/gpu/drm_thread_proxy.h
+++ b/ui/ozone/platform/drm/gpu/drm_thread_proxy.h
@@ -45,8 +45,8 @@
   void GetScanoutFormats(gfx::AcceleratedWidget widget,
                          std::vector<gfx::BufferFormat>* scanout_formats);
 
-  void AddBinding(ozone::mojom::DeviceCursorRequest request);
-  void AddBindingGpu(ozone::mojom::GpuAdapterRequest request);
+  void AddBindingCursorDevice(ozone::mojom::DeviceCursorRequest request);
+  void AddBindingDrmDevice(ozone::mojom::DrmDeviceRequest request);
 
  private:
   DrmThread drm_thread_;
diff --git a/ui/ozone/platform/drm/host/drm_overlay_manager.cc b/ui/ozone/platform/drm/host/drm_overlay_manager.cc
index 01423bf..34099f1 100644
--- a/ui/ozone/platform/drm/host/drm_overlay_manager.cc
+++ b/ui/ozone/platform/drm/host/drm_overlay_manager.cc
@@ -170,9 +170,10 @@
     }
   }
 
-  if (candidate.is_clipped &&
-      !candidate.clip_rect.Contains(candidate.quad_rect_in_target_space))
+  if (candidate.is_clipped && !candidate.clip_rect.Contains(
+                                  gfx::ToNearestRect(candidate.display_rect))) {
     return false;
+  }
 
   return true;
 }
diff --git a/ui/ozone/platform/drm/mus_thread_proxy.h b/ui/ozone/platform/drm/mus_thread_proxy.h
index 680eb99..49f6b5fa 100644
--- a/ui/ozone/platform/drm/mus_thread_proxy.h
+++ b/ui/ozone/platform/drm/mus_thread_proxy.h
@@ -16,7 +16,7 @@
 #include "ui/ozone/platform/drm/host/drm_cursor.h"
 #include "ui/ozone/platform/drm/host/gpu_thread_adapter.h"
 #include "ui/ozone/public/interfaces/device_cursor.mojom.h"
-#include "ui/ozone/public/interfaces/gpu_adapter.mojom.h"
+#include "ui/ozone/public/interfaces/drm_device.mojom.h"
 
 namespace base {
 class SingleThreadTaskRunner;
@@ -123,8 +123,8 @@
 
   scoped_refptr<base::SingleThreadTaskRunner> ws_task_runner_;
 
-  // Mojo implementation of the GpuAdapter.
-  ui::ozone::mojom::GpuAdapterPtr gpu_adapter_;
+  // Mojo implementation of the DrmDevice.
+  ui::ozone::mojom::DrmDevicePtr gpu_adapter_;
 
   // TODO(rjkroege): Remove this in a subsequent CL (http://crbug.com/620927)
   DrmThread* drm_thread_;  // Not owned.
diff --git a/ui/ozone/platform/drm/ozone_platform_gbm.cc b/ui/ozone/platform/drm/ozone_platform_gbm.cc
index 748a918..e4152dd 100644
--- a/ui/ozone/platform/drm/ozone_platform_gbm.cc
+++ b/ui/ozone/platform/drm/ozone_platform_gbm.cc
@@ -117,8 +117,8 @@
                    weak_factory_.GetWeakPtr()),
         gpu_task_runner_);
 
-    registry->AddInterface<ozone::mojom::GpuAdapter>(
-        base::Bind(&OzonePlatformGbm::CreateGpuAdapterBinding,
+    registry->AddInterface<ozone::mojom::DrmDevice>(
+        base::Bind(&OzonePlatformGbm::CreateDrmDeviceBinding,
                    weak_factory_.GetWeakPtr()),
         gpu_task_runner_);
   }
@@ -126,17 +126,17 @@
       ozone::mojom::DeviceCursorRequest request,
       const service_manager::BindSourceInfo& source_info) {
     if (drm_thread_proxy_)
-      drm_thread_proxy_->AddBinding(std::move(request));
+      drm_thread_proxy_->AddBindingCursorDevice(std::move(request));
     else
       pending_cursor_requests_.push_back(std::move(request));
   }
 
-  // service_manager::InterfaceFactory<ozone::mojom::GpuAdapter>:
-  void CreateGpuAdapterBinding(
-      ozone::mojom::GpuAdapterRequest request,
+  // service_manager::InterfaceFactory<ozone::mojom::DrmDevice>:
+  void CreateDrmDeviceBinding(
+      ozone::mojom::DrmDeviceRequest request,
       const service_manager::BindSourceInfo& source_info) {
     if (drm_thread_proxy_)
-      drm_thread_proxy_->AddBindingGpu(std::move(request));
+      drm_thread_proxy_->AddBindingDrmDevice(std::move(request));
     else
       pending_gpu_adapter_requests_.push_back(std::move(request));
   }
@@ -250,10 +250,10 @@
     // incoming binding requests until the GPU thread is running and play them
     // back here.
     for (auto& request : pending_cursor_requests_)
-      drm_thread_proxy_->AddBinding(std::move(request));
+      drm_thread_proxy_->AddBindingCursorDevice(std::move(request));
     pending_cursor_requests_.clear();
     for (auto& request : pending_gpu_adapter_requests_)
-      drm_thread_proxy_->AddBindingGpu(std::move(request));
+      drm_thread_proxy_->AddBindingDrmDevice(std::move(request));
     pending_gpu_adapter_requests_.clear();
   }
 
@@ -273,7 +273,7 @@
   // TODO(rjkroege,sadrul): Once the mus gpu process split happens, this can go
   // away.
   std::vector<ozone::mojom::DeviceCursorRequest> pending_cursor_requests_;
-  std::vector<ozone::mojom::GpuAdapterRequest> pending_gpu_adapter_requests_;
+  std::vector<ozone::mojom::DrmDeviceRequest> pending_gpu_adapter_requests_;
   scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner_;
 
   // Objects in the Browser process.
diff --git a/ui/ozone/public/interfaces/BUILD.gn b/ui/ozone/public/interfaces/BUILD.gn
index 915cfc1..f66bf8a 100644
--- a/ui/ozone/public/interfaces/BUILD.gn
+++ b/ui/ozone/public/interfaces/BUILD.gn
@@ -7,7 +7,7 @@
 mojom("interfaces") {
   sources = [
     "device_cursor.mojom",
-    "gpu_adapter.mojom",
+    "drm_device.mojom",
     "overlay_surface_candidate.mojom",
   ]
 
diff --git a/ui/ozone/public/interfaces/gpu_adapter.mojom b/ui/ozone/public/interfaces/drm_device.mojom
similarity index 89%
rename from ui/ozone/public/interfaces/gpu_adapter.mojom
rename to ui/ozone/public/interfaces/drm_device.mojom
index 21f0871e..0c7ddcd 100644
--- a/ui/ozone/public/interfaces/gpu_adapter.mojom
+++ b/ui/ozone/public/interfaces/drm_device.mojom
@@ -15,13 +15,11 @@
 import "ui/ozone/public/interfaces/overlay_surface_candidate.mojom";
 
 
-// Mus is split into two processes. The GpuAdapter is the interface between
-// Mus-WS and Mus-GPU. Mus-WS is a higher-privilege process while Mus-GPU
-// operates with lower privileges (mirroring the Chrome browser to GPU process
-// relationship.)
-// All functions in GpuAdapter are implemented by the lower privilege GPU
+// The viz process on CrOS implements the DrmDevice
+// service to let the viz host and clients manage DRM displays.
+// All functions in DrmDevice are implemented by the lower privilege viz
 // process.
-interface GpuAdapter {
+interface DrmDevice {
   // Creates scanout capable DRM buffers to back |widget|.
   CreateWindow(gfx.mojom.AcceleratedWidget widget);
 
diff --git a/ui/ozone/public/interfaces/overlay_surface_candidate.mojom b/ui/ozone/public/interfaces/overlay_surface_candidate.mojom
index e65e0d9..28a65d9e 100644
--- a/ui/ozone/public/interfaces/overlay_surface_candidate.mojom
+++ b/ui/ozone/public/interfaces/overlay_surface_candidate.mojom
@@ -28,8 +28,6 @@
   gfx.mojom.RectF display_rect;
   // Crop within the buffer to be placed inside |display_rect|.
   gfx.mojom.RectF crop_rect;
-  // Quad geometry rect after applying the quad_transform().
-  gfx.mojom.Rect quad_rect_in_target_space;
   // Clip rect in the target content space after composition.
   gfx.mojom.Rect clip_rect;
   // If the quad is clipped after composition.
diff --git a/ui/ozone/public/interfaces/overlay_surface_candidate_struct_traits.h b/ui/ozone/public/interfaces/overlay_surface_candidate_struct_traits.h
index d2211d9..3576ee8 100644
--- a/ui/ozone/public/interfaces/overlay_surface_candidate_struct_traits.h
+++ b/ui/ozone/public/interfaces/overlay_surface_candidate_struct_traits.h
@@ -72,11 +72,6 @@
     return osc.crop_rect;
   }
 
-  static const gfx::Rect& quad_rect_in_target_space(
-      const ui::OverlaySurfaceCandidate& osc) {
-    return osc.quad_rect_in_target_space;
-  }
-
   static const gfx::Rect& clip_rect(const ui::OverlaySurfaceCandidate& osc) {
     return osc.clip_rect;
   }
@@ -103,7 +98,6 @@
            data.ReadBufferSize(&out->buffer_size) &&
            data.ReadDisplayRect(&out->display_rect) &&
            data.ReadCropRect(&out->crop_rect) &&
-           data.ReadQuadRectInTargetSpace(&out->quad_rect_in_target_space) &&
            data.ReadClipRect(&out->clip_rect);
   }
 };
diff --git a/ui/ozone/public/interfaces/overlay_surface_candidate_struct_traits_unittest.cc b/ui/ozone/public/interfaces/overlay_surface_candidate_struct_traits_unittest.cc
index 1790d95..a8d8c5b 100644
--- a/ui/ozone/public/interfaces/overlay_surface_candidate_struct_traits_unittest.cc
+++ b/ui/ozone/public/interfaces/overlay_surface_candidate_struct_traits_unittest.cc
@@ -29,7 +29,6 @@
   input.buffer_size = gfx::Size(6, 7);
   input.display_rect = gfx::RectF(1., 2., 3., 4.);
   input.crop_rect = gfx::RectF(10., 20., 30., 40.);
-  input.quad_rect_in_target_space = gfx::Rect(101, 201, 301, 401);
   input.clip_rect = gfx::Rect(11, 21, 31, 41);
   input.is_clipped = true;
   input.plane_z_order = 42;
@@ -47,7 +46,6 @@
   EXPECT_EQ(input.buffer_size, output.buffer_size);
   EXPECT_EQ(input.display_rect, output.display_rect);
   EXPECT_EQ(input.crop_rect, output.crop_rect);
-  EXPECT_EQ(input.quad_rect_in_target_space, output.quad_rect_in_target_space);
   EXPECT_EQ(input.clip_rect, output.clip_rect);
   EXPECT_EQ(input.is_clipped, output.is_clipped);
   EXPECT_EQ(input.plane_z_order, output.plane_z_order);
diff --git a/ui/ozone/public/overlay_surface_candidate.h b/ui/ozone/public/overlay_surface_candidate.h
index 20b405b..aee7095 100644
--- a/ui/ozone/public/overlay_surface_candidate.h
+++ b/ui/ozone/public/overlay_surface_candidate.h
@@ -43,8 +43,6 @@
   gfx::RectF display_rect;
   // Crop within the buffer to be placed inside |display_rect|.
   gfx::RectF crop_rect;
-  // Quad geometry rect after applying the quad_transform().
-  gfx::Rect quad_rect_in_target_space;
   // Clip rect in the target content space after composition.
   gfx::Rect clip_rect;
   // If the quad is clipped after composition.
@@ -63,4 +61,4 @@
 
 }  // namespace ui
 
-#endif  // UI_OZONE_PUBLIC_OVERLAY_SURFACE_CANDIDATE_H_
\ No newline at end of file
+#endif  // UI_OZONE_PUBLIC_OVERLAY_SURFACE_CANDIDATE_H_
diff --git a/ui/views/cocoa/bridged_native_widget.h b/ui/views/cocoa/bridged_native_widget.h
index 372c1ea..bf32252 100644
--- a/ui/views/cocoa/bridged_native_widget.h
+++ b/ui/views/cocoa/bridged_native_widget.h
@@ -254,6 +254,9 @@
   // update its draggable region.
   void SetDraggable(bool draggable);
 
+  // Called by |mouse_down_monitor_| to close a bubble.
+  void OnRightMouseDownWithBubble(NSEvent* event);
+
   // Overridden from CocoaMouseCaptureDelegate:
   void PostCapturedEvent(NSEvent* event) override;
   void OnMouseCaptureLost() override;
@@ -335,6 +338,9 @@
   // the compositor arrives to avoid "blinking".
   bool initial_visibility_suppressed_ = false;
 
+  // Right mouse down monitor for bubble widget.
+  id mouse_down_monitor_;
+
   AssociatedViews associated_views_;
 
   DISALLOW_COPY_AND_ASSIGN(BridgedNativeWidget);
diff --git a/ui/views/cocoa/bridged_native_widget.mm b/ui/views/cocoa/bridged_native_widget.mm
index 7d82128..132ca1e4 100644
--- a/ui/views/cocoa/bridged_native_widget.mm
+++ b/ui/views/cocoa/bridged_native_widget.mm
@@ -373,7 +373,8 @@
       target_fullscreen_state_(false),
       in_fullscreen_transition_(false),
       window_visible_(false),
-      wants_to_be_visible_(false) {
+      wants_to_be_visible_(false),
+      mouse_down_monitor_(nullptr) {
   if (BridgedNativeWidget::ShouldUseDragEventMonitor())
     SetupDragEventMonitor();
 
@@ -421,6 +422,17 @@
              name:NSControlTintDidChangeNotification
            object:nil];
 
+  // Right-clicks outside a bubble should dismiss them, but that doesn't cause
+  // loss of focus on Mac, so add an event monitor to detect.
+  if (params.type == Widget::InitParams::TYPE_BUBBLE) {
+    mouse_down_monitor_ = [NSEvent
+        addLocalMonitorForEventsMatchingMask:NSRightMouseDownMask
+        handler:^NSEvent* (NSEvent* event) {
+          OnRightMouseDownWithBubble(event);
+          return event;
+        }];
+  }
+
   // Validate the window's initial state, otherwise the bridge's initial
   // tracking state will be incorrect.
   DCHECK(![window_ isVisible]);
@@ -743,6 +755,10 @@
     parent_ = nullptr;
   }
   [[NSNotificationCenter defaultCenter] removeObserver:window_delegate_];
+  if (mouse_down_monitor_) {
+    [NSEvent removeMonitor:mouse_down_monitor_];
+    mouse_down_monitor_ = nullptr;
+  }
   [window_ setDelegate:nil];
   native_widget_mac_->OnWindowDestroyed();
   // Note: |this| is deleted here.
@@ -1490,4 +1506,26 @@
   [window_ setMovableByWindowBackground:YES];
 }
 
+void BridgedNativeWidget::OnRightMouseDownWithBubble(NSEvent* event) {
+  NSWindow* target = [event window];
+  if ([target isSheet])
+    return;
+
+  // Do not close the bubble if the event happened on a window with a higher
+  // level.  For example, the content of a browser action bubble opens a
+  // calendar picker window with NSPopUpMenuWindowLevel, and a date selection
+  // closes the picker window, but it should not close the bubble.
+  if ([target level] > [window_ level])
+    return;
+
+  // If the event is in |window_|'s hierarchy, do not close the bubble.
+  while (target) {
+    if (target == window_.get())
+      return;
+    target = [target parentWindow];
+  }
+
+  OnWindowKeyStatusChangedTo(false);
+}
+
 }  // namespace views
diff --git a/ui/views/widget/native_widget_mac_interactive_uitest.mm b/ui/views/widget/native_widget_mac_interactive_uitest.mm
index c29fe04..4e8cf2b6 100644
--- a/ui/views/widget/native_widget_mac_interactive_uitest.mm
+++ b/ui/views/widget/native_widget_mac_interactive_uitest.mm
@@ -11,6 +11,7 @@
 #include "base/macros.h"
 #include "ui/base/test/ui_controls.h"
 #import "ui/base/test/windowed_nsnotification_observer.h"
+#import "ui/events/test/cocoa_test_event_utils.h"
 #include "ui/views/bubble/bubble_dialog_delegate.h"
 #include "ui/views/test/test_widget_observer.h"
 #include "ui/views/test/widget_test.h"
@@ -221,6 +222,57 @@
   parent_widget->CloseNow();
 }
 
+// Test that bubble widgets are dismissed on right mouse down.
+TEST_F(NativeWidgetMacInteractiveUITest, BubbleDismiss) {
+  Widget* parent_widget = CreateTopLevelPlatformWidget();
+  parent_widget->SetBounds(gfx::Rect(100, 100, 100, 100));
+  ShowKeyWindow(parent_widget);
+
+  Widget* bubble_widget =
+      BubbleDialogDelegateView::CreateBubble(new TestBubbleView(parent_widget));
+  ShowKeyWindow(bubble_widget);
+
+  // First, test with LeftMouseDown in the parent window.
+  NSEvent* mouse_down = cocoa_test_event_utils::LeftMouseDownAtPointInWindow(
+      NSMakePoint(50, 50), parent_widget->GetNativeWindow());
+  [NSApp sendEvent:mouse_down];
+  EXPECT_TRUE(bubble_widget->IsClosed());
+
+  bubble_widget =
+      BubbleDialogDelegateView::CreateBubble(new TestBubbleView(parent_widget));
+  ShowKeyWindow(bubble_widget);
+
+  // Test with RightMouseDown in the parent window.
+  mouse_down = cocoa_test_event_utils::RightMouseDownAtPointInWindow(
+      NSMakePoint(50, 50), parent_widget->GetNativeWindow());
+  [NSApp sendEvent:mouse_down];
+  EXPECT_TRUE(bubble_widget->IsClosed());
+
+  bubble_widget =
+      BubbleDialogDelegateView::CreateBubble(new TestBubbleView(parent_widget));
+  ShowKeyWindow(bubble_widget);
+
+  // Test with RightMouseDown in the bubble (bubble should stay open).
+  mouse_down = cocoa_test_event_utils::RightMouseDownAtPointInWindow(
+      NSMakePoint(50, 50), bubble_widget->GetNativeWindow());
+  [NSApp sendEvent:mouse_down];
+  EXPECT_FALSE(bubble_widget->IsClosed());
+  bubble_widget->CloseNow();
+
+  // Test with RightMouseDown when set_close_on_deactivate(false).
+  TestBubbleView* bubble_view = new TestBubbleView(parent_widget);
+  bubble_view->set_close_on_deactivate(false);
+  bubble_widget = BubbleDialogDelegateView::CreateBubble(bubble_view);
+  ShowKeyWindow(bubble_widget);
+
+  mouse_down = cocoa_test_event_utils::RightMouseDownAtPointInWindow(
+      NSMakePoint(50, 50), parent_widget->GetNativeWindow());
+  [NSApp sendEvent:mouse_down];
+  EXPECT_FALSE(bubble_widget->IsClosed());
+
+  parent_widget->CloseNow();
+}
+
 INSTANTIATE_TEST_CASE_P(NativeWidgetMacInteractiveUITestInstance,
                         NativeWidgetMacInteractiveUITest,
                         ::testing::Bool());
diff --git a/ui/webui/resources/cr_elements/compiled_resources2.gyp b/ui/webui/resources/cr_elements/compiled_resources2.gyp
index cd7896a..89de688 100644
--- a/ui/webui/resources/cr_elements/compiled_resources2.gyp
+++ b/ui/webui/resources/cr_elements/compiled_resources2.gyp
@@ -13,6 +13,7 @@
         'cr_dialog/compiled_resources2.gyp:*',
         'cr_drawer/compiled_resources2.gyp:*',
         'cr_expand_button/compiled_resources2.gyp:*',
+        'cr_link_row/compiled_resources2.gyp:*',
         'cr_profile_avatar_selector/compiled_resources2.gyp:*',
         'policy/compiled_resources2.gyp:*',
       ],
diff --git a/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.html b/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.html
index 7e4a5ab..05ca3cc1 100644
--- a/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.html
+++ b/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.html
@@ -24,6 +24,7 @@
       :host ::content .dropdown-item {
         background: none;
         border: none;
+        border-radius: 0;
         box-sizing: border-box;
         color: var(--paper-grey-900);
         font: inherit;
diff --git a/ui/webui/resources/cr_elements/cr_link_row/compiled_resources2.gyp b/ui/webui/resources/cr_elements/cr_link_row/compiled_resources2.gyp
new file mode 100644
index 0000000..11ed485f7
--- /dev/null
+++ b/ui/webui/resources/cr_elements/cr_link_row/compiled_resources2.gyp
@@ -0,0 +1,13 @@
+# 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.
+{
+  'targets': [
+    {
+      'target_name': 'cr_link_row',
+      'dependencies': [
+      ],
+      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+    },
+  ],
+}
diff --git a/ui/webui/resources/cr_elements/cr_link_row/cr_link_row.html b/ui/webui/resources/cr_elements/cr_link_row/cr_link_row.html
new file mode 100644
index 0000000..51ffc4e
--- /dev/null
+++ b/ui/webui/resources/cr_elements/cr_link_row/cr_link_row.html
@@ -0,0 +1,73 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="chrome://resources/cr_elements/cr_icons_css.html">
+<link rel="import" href="chrome://resources/cr_elements/hidden_style_css.html">
+<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/default-theme.html">
+
+<dom-module id="cr-link-row">
+  <template strip-whitespace="">
+    <style include="cr-hidden-style cr-icons">
+      :host {
+        background: none;
+        border: none;
+        color: inherit;
+        cursor: pointer;
+        line-height: 154%;  /* 20px. */
+        margin: 0;
+        outline: none;
+        padding: 0;
+        position: relative;
+        width: 100%;
+        @apply(--cr-section);
+      }
+
+      :host(.continuation),
+      :host(.first) {
+        border-top: none;
+      }
+
+      :host([disabled]) {
+        color: var(--paper-grey-500);
+        cursor: auto;
+        pointer-events: none;
+      }
+
+      #label,
+      #subLabel {
+        display: flex;
+      }
+
+      #labelWrapper {
+        flex: 1;
+        flex-basis: 0.000000001px;
+      }
+
+      #outer {
+        align-items: center;
+        display: flex;
+        min-height: var(--cr-section-two-line-min-height);
+        width: 100%;
+      }
+
+      #outer[noSubLabel] {
+        min-height: var(--cr-section-min-height);
+      }
+
+      #subLabel {
+        /* TODO(dschuyler): replace with: @apply(--cr-secondary-text); */
+        color: var(--paper-grey-600);
+        font-weight: 400;
+      }
+    </style>
+    <div id="outer" noSubLabel$="[[!subLabel]]">
+      <div id="labelWrapper" hidden="[[!label]]">
+        <div id="label" class="label">[[label]]</div>
+        <div id="subLabel" class="secondary label">[[subLabel]]</div>
+      </div>
+      <button class$="[[iconClass]]" is="paper-icon-button-light"></button>
+    </div>
+  </template>
+  <script src="cr_link_row.js"></script>
+</dom-module>
diff --git a/ui/webui/resources/cr_elements/cr_link_row/cr_link_row.js b/ui/webui/resources/cr_elements/cr_link_row/cr_link_row.js
new file mode 100644
index 0000000..e700b6d9
--- /dev/null
+++ b/ui/webui/resources/cr_elements/cr_link_row/cr_link_row.js
@@ -0,0 +1,27 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview
+ * A link row is a UI element similar to a button, though usually wider than a
+ * button (taking up the whole 'row'). The name link comes from the intended use
+ * of this element to take the user to another page in the app or to an external
+ * page (somewhat like an HTML link).
+ */
+Polymer({
+  is: 'cr-link-row',
+  extends: 'button',
+
+  properties: {
+    iconClass: String,
+
+    label: String,
+
+    subLabel: {
+      type: String,
+      /* Value used for noSubLabel attribute. */
+      value: '',
+    },
+  },
+});
diff --git a/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.html b/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.html
index 5b38933..dd002fb 100644
--- a/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.html
+++ b/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.html
@@ -151,7 +151,6 @@
           on-blur="onInputBlur_"
           incremental
           autofocus>
-      </input>
     </div>
     <template is="dom-if" if="[[hasSearchText]]">
       <button is="paper-icon-button-light" class="icon-cancel-toolbar"
diff --git a/ui/webui/resources/cr_elements/shared_vars_css.html b/ui/webui/resources/cr_elements/shared_vars_css.html
index 2f1ceff..4c773e5e 100644
--- a/ui/webui/resources/cr_elements/shared_vars_css.html
+++ b/ui/webui/resources/cr_elements/shared_vars_css.html
@@ -50,6 +50,9 @@
     --cr-section-three-line-min-height: 84px;
 
     --cr-section-padding: 20px;
+    --cr-section-indent-width: 40px;
+    --cr-section-indent-padding: calc(
+        var(--cr-section-padding) + var(--cr-section-indent-width));
 
     --cr-section: {
       align-items: center;
diff --git a/ui/webui/resources/cr_elements_resources.grdp b/ui/webui/resources/cr_elements_resources.grdp
index da62fc8..d7f4a17 100644
--- a/ui/webui/resources/cr_elements_resources.grdp
+++ b/ui/webui/resources/cr_elements_resources.grdp
@@ -41,6 +41,12 @@
   <structure name="IDR_CR_ELEMENTS_CR_LAZY_RENDER_JS"
              file="../../webui/resources/cr_elements/cr_lazy_render/cr_lazy_render.js"
              type="chrome_html" />
+  <structure name="IDR_CR_ELEMENTS_CR_LINK_ROW_HTML"
+             file="../../webui/resources/cr_elements/cr_link_row/cr_link_row.html"
+             type="chrome_html" />
+  <structure name="IDR_CR_ELEMENTS_CR_LINK_ROW_JS"
+             file="../../webui/resources/cr_elements/cr_link_row/cr_link_row.js"
+             type="chrome_html" />
   <if expr="chromeos">
     <structure name="IDR_CR_ELEMENTS_CHROMEOS_CR_PICTURE_CR_CAMERA_HTML"
                file="../../webui/resources/cr_elements/chromeos/cr_picture/cr_camera.html"
diff --git a/ui/webui/resources/css/widgets.css b/ui/webui/resources/css/widgets.css
index 997bfc0..41930471 100644
--- a/ui/webui/resources/css/widgets.css
+++ b/ui/webui/resources/css/widgets.css
@@ -249,7 +249,7 @@
  *
  *   <div class="checkbox">
  *     <label>
- *       <input type="checkbox"></input>
+ *       <input type="checkbox">
  *       <span>
  *     </label>
  *   </div>