diff --git a/DEPS b/DEPS
index dea6d526..d9100da 100644
--- a/DEPS
+++ b/DEPS
@@ -44,7 +44,7 @@
   # 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': '4bb4a24ef43b3cad1288c7f4299af118c13db4c8',
+  'v8_revision': 'dccdc02878d7136d2d4b6ca80bd025294cf1c7f8',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -52,7 +52,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '9216a6e26db957681faefc40884e8bf21fde5063',
+  'angle_revision': 'cae72d6ab32cca4c9ce4af6a10bc6f4b89138ed4',
   # 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': 'a64cd6c86438636b031e1204057b27a8b9673296',
+  'pdfium_revision': '5f34d479d06ebab9079c2d0704dee872cc45dd86',
   # 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.
@@ -403,7 +403,7 @@
 
     # For Linux and Chromium OS.
     'src/third_party/cros_system_api':
-      Var('chromium_git') + '/chromiumos/platform/system_api.git' + '@' + '6b09df23f8a968fc72956218a62302b89d5334b1',
+      Var('chromium_git') + '/chromiumos/platform/system_api.git' + '@' + 'ff270ca217a85f02bddcdd78d8cbc9d6a4641572',
 
     # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
     'src/third_party/chromite':
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn
index 3f9ce275..6d4e39c7 100644
--- a/android_webview/BUILD.gn
+++ b/android_webview/BUILD.gn
@@ -683,6 +683,7 @@
     "//base",
     "//base/third_party/dynamic_annotations:dynamic_annotations",
     "//cc/surfaces",
+    "//components/autofill/android:provider",
     "//components/autofill/content/browser",
     "//components/autofill/content/renderer",
     "//components/cdm/browser",
diff --git a/android_webview/browser/DEPS b/android_webview/browser/DEPS
index da57d62..1bdf66c6 100644
--- a/android_webview/browser/DEPS
+++ b/android_webview/browser/DEPS
@@ -9,6 +9,7 @@
   "+cc",
   "-cc/blink",
 
+  "+components/autofill/android",
   "+components/autofill/content/browser",
   "+components/autofill/core/browser",
   "+components/autofill/core/common",
diff --git a/android_webview/browser/aw_contents.cc b/android_webview/browser/aw_contents.cc
index f03fd65..ef985d22 100644
--- a/android_webview/browser/aw_contents.cc
+++ b/android_webview/browser/aw_contents.cc
@@ -51,6 +51,7 @@
 #include "base/strings/string16.h"
 #include "base/supports_user_data.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "components/autofill/android/autofill_provider_android.h"
 #include "components/autofill/content/browser/content_autofill_driver_factory.h"
 #include "components/autofill/core/browser/autofill_manager.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
@@ -248,7 +249,8 @@
     const JavaParamRef<jobject>& web_contents_delegate,
     const JavaParamRef<jobject>& contents_client_bridge,
     const JavaParamRef<jobject>& io_thread_client,
-    const JavaParamRef<jobject>& intercept_navigation_delegate) {
+    const JavaParamRef<jobject>& intercept_navigation_delegate,
+    const JavaParamRef<jobject>& autofill_provider) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   // The |aw_content| param is technically spurious as it duplicates |obj| but
   // is passed over anyway to make the binding more explicit.
@@ -269,6 +271,11 @@
       web_contents_.get(), base::MakeUnique<InterceptNavigationDelegate>(
                                env, intercept_navigation_delegate));
 
+  if (!autofill_provider.is_null()) {
+    autofill_provider_ = base::MakeUnique<autofill::AutofillProviderAndroid>(
+        autofill_provider, web_contents_.get());
+  }
+
   // Finally, having setup the associations, release any deferred requests
   for (content::RenderFrameHost* rfh : web_contents_->GetAllFrames()) {
     int render_process_id = rfh->GetProcess()->GetID();
@@ -289,20 +296,29 @@
   }
 }
 
-void AwContents::InitAutofillIfNecessary(bool enabled) {
-  // Do not initialize if the feature is not enabled.
-  if (!enabled)
-    return;
+void AwContents::InitAutofillIfNecessary(bool autocomplete_enabled) {
   // Check if the autofill driver factory already exists.
   content::WebContents* web_contents = web_contents_.get();
   if (ContentAutofillDriverFactory::FromWebContents(web_contents))
     return;
 
+  // Check if AutofillProvider is available.
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+  if (obj.is_null())
+    return;
+
+  // Just return, if the app neither runs on O sdk nor enables autocomplete.
+  if (!autofill_provider_ && !autocomplete_enabled)
+    return;
+
   AwAutofillClient::CreateForWebContents(web_contents);
   ContentAutofillDriverFactory::CreateForWebContentsAndDelegate(
       web_contents, AwAutofillClient::FromWebContents(web_contents),
       base::android::GetDefaultLocaleString(),
-      AutofillManager::DISABLE_AUTOFILL_DOWNLOAD_MANAGER);
+      AutofillManager::DISABLE_AUTOFILL_DOWNLOAD_MANAGER,
+      autofill_provider_.get());
 }
 
 void AwContents::SetAwAutofillClient(const JavaRef<jobject>& client) {
@@ -1354,6 +1370,12 @@
   web_contents_->ResumeLoadingCreatedWebContents();
 }
 
+jlong AwContents::GetAutofillProvider(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& obj) {
+  return reinterpret_cast<jlong>(autofill_provider_.get());
+}
+
 void SetShouldDownloadFavicons(JNIEnv* env,
                                const JavaParamRef<jclass>& jclazz) {
   g_should_download_favicons = true;
diff --git a/android_webview/browser/aw_contents.h b/android_webview/browser/aw_contents.h
index d4d98474a..f731590 100644
--- a/android_webview/browser/aw_contents.h
+++ b/android_webview/browser/aw_contents.h
@@ -35,6 +35,10 @@
 class SkBitmap;
 class TabContents;
 
+namespace autofill {
+class AutofillProvider;
+}
+
 namespace content {
 class WebContents;
 }
@@ -106,8 +110,8 @@
       const base::android::JavaParamRef<jobject>& web_contents_delegate,
       const base::android::JavaParamRef<jobject>& contents_client_bridge,
       const base::android::JavaParamRef<jobject>& io_thread_client,
-      const base::android::JavaParamRef<jobject>&
-          intercept_navigation_delegate);
+      const base::android::JavaParamRef<jobject>& intercept_navigation_delegate,
+      const base::android::JavaParamRef<jobject>& autofill_provider);
   base::android::ScopedJavaLocalRef<jobject> GetWebContents(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj);
@@ -347,6 +351,9 @@
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj);
 
+  jlong GetAutofillProvider(JNIEnv* env,
+                            const base::android::JavaParamRef<jobject>& obj);
+
   // content::WebContentsObserver overrides
   void RenderViewHostChanged(content::RenderViewHost* old_host,
                              content::RenderViewHost* new_host) override;
@@ -372,7 +379,7 @@
   bool OnRenderProcessGoneDetail(int child_process_id, bool crashed) override;
 
  private:
-  void InitAutofillIfNecessary(bool enabled);
+  void InitAutofillIfNecessary(bool autocomplete_enabled);
 
   // Geolocation API support
   void ShowGeolocationPrompt(const GURL& origin, base::Callback<void(bool)>);
@@ -400,6 +407,7 @@
   std::unique_ptr<AwContents> pending_contents_;
   std::unique_ptr<AwPdfExporter> pdf_exporter_;
   std::unique_ptr<PermissionRequestHandler> permission_request_handler_;
+  std::unique_ptr<autofill::AutofillProvider> autofill_provider_;
 
   // GURL is supplied by the content layer as requesting frame.
   // Callback is supplied by the content layer, and is invoked with the result
diff --git a/android_webview/glue/glue.gni b/android_webview/glue/glue.gni
index 7da54cf..7591610 100644
--- a/android_webview/glue/glue.gni
+++ b/android_webview/glue/glue.gni
@@ -9,6 +9,7 @@
   "//android_webview:android_webview_commandline_java",
   "//android_webview:android_webview_platform_services_java",
   "//base:base_java",
+  "//components/autofill/android:autofill_java",
   "//content/public/android:content_java",
   "//net/android:net_java",
   "//ui/android:ui_java",
diff --git a/android_webview/glue/java/DEPS b/android_webview/glue/java/DEPS
index 794ecd7e..c06c9e5 100644
--- a/android_webview/glue/java/DEPS
+++ b/android_webview/glue/java/DEPS
@@ -1,5 +1,6 @@
 include_rules = [
   "+android_webview/java",
   "+base/android/java",
+  "+components/autofill/android/java",
   "+content/public/android/java",
 ]
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 7d45271..210215e 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
@@ -57,6 +57,7 @@
 import org.chromium.android_webview.ResourcesContextWrapperFactory;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.annotations.SuppressFBWarnings;
+import org.chromium.components.autofill.AutofillProvider;
 import org.chromium.content.browser.SmartClipProvider;
 import org.chromium.content_public.browser.NavigationHistory;
 
@@ -101,7 +102,7 @@
 
     private final int mAppTargetSdkVersion;
 
-    private WebViewChromiumFactoryProvider mFactory;
+    protected WebViewChromiumFactoryProvider mFactory;
 
     private final boolean mShouldDisableThreadChecking;
 
@@ -230,7 +231,14 @@
 
         mAwContents = new AwContents(mFactory.getBrowserContextOnUiThread(), mWebView, mContext,
                 new InternalAccessAdapter(), new WebViewNativeDrawGLFunctorFactory(),
-                mContentsClientAdapter, mWebSettings.getAwSettings());
+                mContentsClientAdapter, mWebSettings.getAwSettings(),
+                new AwContents.DependencyFactory() {
+                    @Override
+                    public AutofillProvider createAutofillProvider(
+                            Context context, ViewGroup containerView) {
+                        return mFactory.createAutofillProvider(context, mWebView);
+                    }
+                });
 
         if (mAppTargetSdkVersion >= Build.VERSION_CODES.KITKAT) {
             // On KK and above, favicons are automatically downloaded as the method
@@ -253,7 +261,7 @@
                 "Calling View methods on another thread than the UI thread.");
     }
 
-    private boolean checkNeedsPost() {
+    protected boolean checkNeedsPost() {
         boolean needsPost = !mFactory.hasStarted() || !ThreadUtils.runningOnUiThread();
         if (!needsPost && mAwContents == null) {
             throw new IllegalStateException("AwContents must be created if we are not posting!");
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 9d0138f..abd1f8c 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
@@ -20,6 +20,7 @@
 import android.os.UserManager;
 import android.provider.Settings;
 import android.util.Log;
+import android.view.ViewGroup;
 import android.webkit.CookieManager;
 import android.webkit.GeolocationPermissions;
 import android.webkit.ServiceWorkerController;
@@ -62,6 +63,7 @@
 import org.chromium.base.library_loader.LibraryProcessType;
 import org.chromium.base.library_loader.NativeLibraries;
 import org.chromium.base.library_loader.ProcessInitException;
+import org.chromium.components.autofill.AutofillProvider;
 import org.chromium.content.browser.input.LGEmailActionModeWorkaround;
 import org.chromium.net.NetworkChangeNotifier;
 
@@ -708,4 +710,8 @@
             Context context) {
         return new WebViewContentsClientAdapter(webView, context, mWebViewDelegate);
     }
+
+    AutofillProvider createAutofillProvider(Context context, ViewGroup containerView) {
+        return null;
+    }
 }
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 64cd9314..e508c8a 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContents.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -30,6 +30,7 @@
 import android.text.TextUtils;
 import android.util.Base64;
 import android.util.Pair;
+import android.util.SparseArray;
 import android.view.DragEvent;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
@@ -57,6 +58,7 @@
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.annotations.SuppressFBWarnings;
+import org.chromium.components.autofill.AutofillProvider;
 import org.chromium.components.navigation_interception.InterceptNavigationDelegate;
 import org.chromium.components.navigation_interception.NavigationParams;
 import org.chromium.content.browser.AppWebMessagePort;
@@ -247,6 +249,10 @@
                 AwScrollOffsetManager.Delegate delegate) {
             return new AwScrollOffsetManager(delegate);
         }
+
+        public AutofillProvider createAutofillProvider(Context context, ViewGroup containerView) {
+            return null;
+        }
     }
 
     /**
@@ -364,6 +370,8 @@
     // Do not use directly, call isNoOperation() instead.
     private boolean mIsNoOperation;
 
+    private AutofillProvider mAutofillProvider;
+
     private static String sCurrentLocales = "";
 
     private Paint mPaintForNWorkaround;
@@ -753,6 +761,7 @@
 
         mHandler = new Handler();
         mContext = context;
+        mAutofillProvider = dependencyFactory.createAutofillProvider(context, mContainerView);
         mAppTargetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
         mInternalAccessAdapter = internalAccessAdapter;
         mNativeDrawGLFunctorFactory = nativeDrawGLFunctorFactory;
@@ -962,6 +971,7 @@
         awViewMethodsImpl.onWindowFocusChanged(mContainerView.hasWindowFocus());
         awViewMethodsImpl.onFocusChanged(mContainerView.hasFocus(), 0, null);
         mContainerView.requestLayout();
+        if (mAutofillProvider != null) mAutofillProvider.onContainerViewChanged(mContainerView);
     }
 
     // This class destroys the WindowAndroid when after it is gc-ed.
@@ -1069,11 +1079,12 @@
                 mInternalAccessAdapter, webContents, new AwGestureStateListener(),
                 mWindowAndroid.getWindowAndroid());
         nativeSetJavaPeers(mNativeAwContents, this, mWebContentsDelegate, mContentsClientBridge,
-                mIoThreadClient, mInterceptNavigationDelegate);
+                mIoThreadClient, mInterceptNavigationDelegate, mAutofillProvider);
         mWebContents = mContentViewCore.getWebContents();
         mNavigationController = mWebContents.getNavigationController();
         installWebContentsObserver();
         mSettings.setWebContents(webContents);
+        if (mAutofillProvider != null) mAutofillProvider.setWebContents(webContents);
 
         if (textClassifier != null) mContentViewCore.setTextClassifier(textClassifier);
 
@@ -2336,6 +2347,18 @@
         mContentViewCore.onProvideVirtualStructure(structure, true);
     }
 
+    public void onProvideAutoFillVirtualStructure(ViewStructure structure, int flags) {
+        if (mAutofillProvider != null) {
+            mAutofillProvider.onProvideAutoFillVirtualStructure(structure, flags);
+        }
+    }
+
+    public void autofill(final SparseArray<String> values) {
+        if (mAutofillProvider != null) {
+            mAutofillProvider.autofill(values);
+        }
+    }
+
     public boolean isSelectActionModeAllowed(int actionModeItem) {
         return (mSettings.getDisabledActionModeMenuItems() & actionModeItem) != actionModeItem;
     }
@@ -3463,9 +3486,9 @@
     private native void nativeCallDontProceedOnInterstitialForTesting(long nativeAwContents);
     private native void nativeSetJavaPeers(long nativeAwContents, AwContents awContents,
             AwWebContentsDelegate webViewWebContentsDelegate,
-            AwContentsClientBridge contentsClientBridge,
-            AwContentsIoThreadClient ioThreadClient,
-            InterceptNavigationDelegate navigationInterceptionDelegate);
+            AwContentsClientBridge contentsClientBridge, AwContentsIoThreadClient ioThreadClient,
+            InterceptNavigationDelegate navigationInterceptionDelegate,
+            AutofillProvider autofillProvider);
     private native WebContents nativeGetWebContents(long nativeAwContents);
     private native void nativeSetAwGLFunctor(long nativeAwContents, long nativeAwGLFunctor);
 
diff --git a/ash/display/display_color_manager_chromeos.cc b/ash/display/display_color_manager_chromeos.cc
index cdfcccc..074043f 100644
--- a/ash/display/display_color_manager_chromeos.cc
+++ b/ash/display/display_color_manager_chromeos.cc
@@ -6,6 +6,8 @@
 
 #include <utility>
 
+#include "ash/public/cpp/config.h"
+#include "ash/shell.h"
 #include "base/bind.h"
 #include "base/files/file_util.h"
 #include "base/logging.h"
@@ -196,6 +198,12 @@
     return;
   }
 
+  // TODO: enable QuirksManager for mash. http://crbug.com/728748. Some tests
+  // don't create the Shell when running this code, hence the
+  // Shell::HasInstance() conditional.
+  if (Shell::HasInstance() && Shell::GetAshConfig() == Config::MASH)
+    return;
+
   quirks::QuirksManager::Get()->RequestIccProfilePath(
       display->product_id(), display->display_name(),
       base::Bind(&DisplayColorManager::FinishLoadCalibrationForDisplay,
diff --git a/ash/system/audio/volume_view.cc b/ash/system/audio/volume_view.cc
index e541e5e..ea4a5d4 100644
--- a/ash/system/audio/volume_view.cc
+++ b/ash/system/audio/volume_view.cc
@@ -100,8 +100,10 @@
     node_data->SetName(
         l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_VOLUME_MUTE));
     node_data->role = ui::AX_ROLE_TOGGLE_BUTTON;
-    if (CrasAudioHandler::Get()->IsOutputMuted())
-      node_data->AddState(ui::AX_STATE_PRESSED);
+    const bool is_pressed = CrasAudioHandler::Get()->IsOutputMuted();
+    node_data->AddIntAttribute(
+        ui::AX_ATTR_CHECKED_STATE,
+        is_pressed ? ui::AX_CHECKED_STATE_TRUE : ui::AX_CHECKED_STATE_FALSE);
   }
 
   views::ImageView* image_;
diff --git a/ash/system/night_light/night_light_toggle_button.cc b/ash/system/night_light/night_light_toggle_button.cc
index ca3eb6e9..97d0444e 100644
--- a/ash/system/night_light/night_light_toggle_button.cc
+++ b/ash/system/night_light/night_light_toggle_button.cc
@@ -60,8 +60,10 @@
   node_data->SetName(
       l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NIGHT_LIGHT));
   node_data->role = ui::AX_ROLE_TOGGLE_BUTTON;
-  if (Shell::Get()->night_light_controller()->GetEnabled())
-    node_data->AddState(ui::AX_STATE_PRESSED);
+  const bool is_pressed = Shell::Get()->night_light_controller()->GetEnabled();
+  node_data->AddIntAttribute(
+      ui::AX_ATTR_CHECKED_STATE,
+      is_pressed ? ui::AX_CHECKED_STATE_TRUE : ui::AX_CHECKED_STATE_FALSE);
 }
 
 }  // namespace ash
diff --git a/base/BUILD.gn b/base/BUILD.gn
index a265f98..679683c 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -1234,6 +1234,7 @@
       "process/launch_posix.cc",
       "process/process_handle_posix.cc",
       "process/process_posix.cc",
+      "rand_util_posix.cc",
     ]
 
     sources += [
@@ -1248,6 +1249,7 @@
       "process/process_fuchsia.cc",
       "process/process_handle_fuchsia.cc",
       "process/process_metrics_fuchsia.cc",
+      "rand_util_fuchsia.cc",
       "sys_info_fuchsia.cc",
       "threading/platform_thread_fuchsia.cc",
       "time/time_conversion_posix.cc",
diff --git a/base/rand_util.h b/base/rand_util.h
index 881dbd50..286d69c 100644
--- a/base/rand_util.h
+++ b/base/rand_util.h
@@ -53,7 +53,7 @@
 // See crypto/ for cryptographically secure random number generation APIs.
 BASE_EXPORT std::string RandBytesAsString(size_t length);
 
-#if defined(OS_POSIX)
+#if defined(OS_POSIX) && !defined(OS_FUCHSIA)
 BASE_EXPORT int GetUrandomFD();
 #endif
 
diff --git a/base/rand_util_fuchsia.cc b/base/rand_util_fuchsia.cc
new file mode 100644
index 0000000..e902d16
--- /dev/null
+++ b/base/rand_util_fuchsia.cc
@@ -0,0 +1,39 @@
+// Copyright 2017 The Chromium 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/rand_util.h"
+
+#include <magenta/syscalls.h>
+
+#include <algorithm>
+
+#include "base/logging.h"
+
+namespace base {
+
+uint64_t RandUint64() {
+  uint64_t number;
+  RandBytes(&number, sizeof(number));
+  return number;
+}
+
+void RandBytes(void* output, size_t output_length) {
+  size_t remaining = output_length;
+  unsigned char* cur = reinterpret_cast<unsigned char*>(output);
+  do {
+    // The syscall has a maximum number of bytes that can be read at once.
+    size_t read_len =
+        std::min(remaining, static_cast<size_t>(MX_CPRNG_DRAW_MAX_LEN));
+
+    size_t actual;
+    mx_status_t status = mx_cprng_draw(cur, read_len, &actual);
+    CHECK(status == NO_ERROR && read_len == actual);
+
+    CHECK(remaining >= actual);
+    remaining -= actual;
+    cur += actual;
+  } while (remaining > 0);
+}
+
+}  // namespace base
diff --git a/base/rand_util_unittest.cc b/base/rand_util_unittest.cc
index 4f46b807..dc61e9f 100644
--- a/base/rand_util_unittest.cc
+++ b/base/rand_util_unittest.cc
@@ -134,6 +134,17 @@
   FAIL() << "Didn't achieve all bit values in maximum number of tries.";
 }
 
+TEST(RandUtilTest, RandBytesLonger) {
+  // Fuchsia can only retrieve 256 bytes of entropy at a time, so make sure we
+  // handle longer requests than that.
+  std::string random_string0 = base::RandBytesAsString(255);
+  EXPECT_EQ(255u, random_string0.size());
+  std::string random_string1 = base::RandBytesAsString(1023);
+  EXPECT_EQ(1023u, random_string1.size());
+  std::string random_string2 = base::RandBytesAsString(4097);
+  EXPECT_EQ(4097u, random_string2.size());
+}
+
 // Benchmark test for RandBytes().  Disabled since it's intentionally slow and
 // does not test anything that isn't already tested by the existing RandBytes()
 // tests.
diff --git a/build/sanitizers/tsan_suppressions.cc b/build/sanitizers/tsan_suppressions.cc
index 4600b3e2..faf1af7 100644
--- a/build/sanitizers/tsan_suppressions.cc
+++ b/build/sanitizers/tsan_suppressions.cc
@@ -246,8 +246,7 @@
     // http://crbug.com/587199
     "race:base::TimerTest_OneShotTimer_CustomTaskRunner_Test::TestBody\n"
     "race:base::TimerSequenceTest_OneShotTimerTaskOnPoolThread_Test::TestBody\n"
-    "race:base::TimerSequenceTest_OneShotTimerUsedAndTaskedOnDifferentPools_"
-    "Test::TestBody\n"
+    "race:base::TimerSequenceTest_OneShotTimerUsedAndTaskedOnDifferentPools\n"
 
     // http://crbug.com/v8/6065
     "race:net::(anonymous namespace)::ProxyResolverV8TracingImpl::RequestImpl"
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index 11e0b15..7aef17d 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -297,6 +297,8 @@
     "resources/resource_pool.h",
     "resources/resource_provider.cc",
     "resources/resource_provider.h",
+    "resources/resource_settings.cc",
+    "resources/resource_settings.h",
     "resources/resource_util.h",
     "resources/returned_resource.h",
     "resources/scoped_resource.cc",
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc
index 0e32438..6b326b8 100644
--- a/cc/layers/picture_layer_impl_unittest.cc
+++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -81,7 +81,7 @@
     LayerTreeSettings settings;
     settings.layer_transforms_should_scale_layer_contents = true;
     settings.create_low_res_tiling = true;
-    settings.buffer_to_texture_target_map =
+    settings.resource_settings.buffer_to_texture_target_map =
         DefaultBufferToTextureTargetMapForTesting();
     return settings;
   }
diff --git a/cc/output/renderer_settings.h b/cc/output/renderer_settings.h
index 9dcdec0..a2576ac 100644
--- a/cc/output/renderer_settings.h
+++ b/cc/output/renderer_settings.h
@@ -8,7 +8,7 @@
 #include <stddef.h>
 
 #include "cc/cc_export.h"
-#include "cc/output/buffer_to_texture_target_map.h"
+#include "cc/resources/resource_settings.h"
 
 namespace cc {
 
@@ -18,6 +18,7 @@
   RendererSettings(const RendererSettings& other);
   ~RendererSettings();
 
+  ResourceSettings resource_settings;
   bool allow_antialiasing = true;
   bool force_antialiasing = false;
   bool force_blending_with_shaders = false;
@@ -29,11 +30,10 @@
   bool show_overdraw_feedback = false;
   bool enable_color_correct_rendering = false;
 
+  // TODO(staraz): Move |refresh_rate| out. It's only used by
+  // TestCompositorFrameSink
   double refresh_rate = 60.0;
   int highp_threshold_min = 0;
-  size_t texture_id_allocation_chunk_size = 64;
-  bool use_gpu_memory_buffer_resources = false;
-  BufferToTextureTargetMap buffer_to_texture_target_map;
 
   // Determines whether we disallow non-exact matches when finding resources
   // in ResourcePool. Only used for layout or pixel tests, as non-deterministic
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc
index 8d5a3fc..2990d57 100644
--- a/cc/resources/resource_provider.cc
+++ b/cc/resources/resource_provider.cc
@@ -374,12 +374,12 @@
 ResourceProvider::Settings::Settings(
     ContextProvider* compositor_context_provider,
     bool delegated_sync_points_required,
-    bool use_gpu_memory_buffer_resources,
-    bool enable_color_correct_rasterization)
-    : default_resource_type(use_gpu_memory_buffer_resources
+    const ResourceSettings& resource_settings)
+    : default_resource_type(resource_settings.use_gpu_memory_buffer_resources
                                 ? RESOURCE_TYPE_GPU_MEMORY_BUFFER
                                 : RESOURCE_TYPE_GL_TEXTURE),
-      enable_color_correct_rasterization(enable_color_correct_rasterization),
+      enable_color_correct_rasterization(
+          resource_settings.enable_color_correct_rasterization),
       delegated_sync_points_required(delegated_sync_points_required) {
   if (!compositor_context_provider) {
     default_resource_type = RESOURCE_TYPE_BITMAP;
@@ -419,15 +419,11 @@
     SharedBitmapManager* shared_bitmap_manager,
     gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
     BlockingTaskRunner* blocking_main_thread_task_runner,
-    size_t id_allocation_chunk_size,
     bool delegated_sync_points_required,
-    bool use_gpu_memory_buffer_resources,
-    bool enable_color_correct_rasterization,
-    const BufferToTextureTargetMap& buffer_to_texture_target_map)
+    const ResourceSettings& resource_settings)
     : settings_(compositor_context_provider,
                 delegated_sync_points_required,
-                use_gpu_memory_buffer_resources,
-                enable_color_correct_rasterization),
+                resource_settings),
       compositor_context_provider_(compositor_context_provider),
       shared_bitmap_manager_(shared_bitmap_manager),
       gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
@@ -435,9 +431,10 @@
       lost_context_provider_(false),
       next_id_(1),
       next_child_(1),
-      buffer_to_texture_target_map_(buffer_to_texture_target_map),
+      buffer_to_texture_target_map_(
+          resource_settings.buffer_to_texture_target_map),
       tracing_id_(g_next_resource_provider_tracing_id.GetNext()) {
-  DCHECK(id_allocation_chunk_size);
+  DCHECK(resource_settings.texture_id_allocation_chunk_size);
   DCHECK(thread_checker_.CalledOnValidThread());
 
   // In certain cases, ThreadTaskRunnerHandle isn't set (Android Webview).
@@ -453,8 +450,8 @@
 
   DCHECK(!texture_id_allocator_);
   GLES2Interface* gl = ContextGL();
-  texture_id_allocator_.reset(
-      new TextureIdAllocator(gl, id_allocation_chunk_size));
+  texture_id_allocator_.reset(new TextureIdAllocator(
+      gl, resource_settings.texture_id_allocation_chunk_size));
 }
 
 ResourceProvider::~ResourceProvider() {
diff --git a/cc/resources/resource_provider.h b/cc/resources/resource_provider.h
index 2b664ff..be8f38f 100644
--- a/cc/resources/resource_provider.h
+++ b/cc/resources/resource_provider.h
@@ -31,6 +31,7 @@
 #include "cc/output/renderer_settings.h"
 #include "cc/resources/release_callback_impl.h"
 #include "cc/resources/resource_format.h"
+#include "cc/resources/resource_settings.h"
 #include "cc/resources/return_callback.h"
 #include "cc/resources/shared_bitmap.h"
 #include "cc/resources/single_release_callback_impl.h"
@@ -80,16 +81,12 @@
     RESOURCE_TYPE_BITMAP,
   };
 
-  ResourceProvider(
-      ContextProvider* compositor_context_provider,
-      SharedBitmapManager* shared_bitmap_manager,
-      gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
-      BlockingTaskRunner* blocking_main_thread_task_runner,
-      size_t id_allocation_chunk_size,
-      bool delegated_sync_points_required,
-      bool use_gpu_memory_buffer_resources,
-      bool enable_color_correct_rasterization,
-      const BufferToTextureTargetMap& buffer_to_texture_target_map);
+  ResourceProvider(ContextProvider* compositor_context_provider,
+                   SharedBitmapManager* shared_bitmap_manager,
+                   gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
+                   BlockingTaskRunner* blocking_main_thread_task_runner,
+                   bool delegated_sync_points_required,
+                   const ResourceSettings& resource_settings);
   ~ResourceProvider() override;
 
   void Initialize();
@@ -765,9 +762,8 @@
   // Holds const settings for the ResourceProvider. Never changed after init.
   struct Settings {
     Settings(ContextProvider* compositor_context_provider,
-             bool delegated_sync_points_required,
-             bool use_gpu_memory_buffer_resources,
-             bool enable_color_correct_rasterization);
+             bool delegated_sync_points_needed,
+             const ResourceSettings& resource_settings);
 
     int max_texture_size = 0;
     bool use_texture_storage_ext = false;
diff --git a/cc/resources/resource_provider_unittest.cc b/cc/resources/resource_provider_unittest.cc
index b804afb..12ecd09 100644
--- a/cc/resources/resource_provider_unittest.cc
+++ b/cc/resources/resource_provider_unittest.cc
@@ -103,6 +103,24 @@
   return shared_bitmap;
 }
 
+static ResourceSettings CreateResourceSettings(
+    size_t texture_id_allocation_chunk_size) {
+  ResourceSettings resource_settings;
+  resource_settings.texture_id_allocation_chunk_size =
+      texture_id_allocation_chunk_size;
+  resource_settings.use_gpu_memory_buffer_resources =
+      kUseGpuMemoryBufferResources;
+  resource_settings.enable_color_correct_rasterization =
+      kEnableColorCorrectRendering;
+  resource_settings.buffer_to_texture_target_map =
+      DefaultBufferToTextureTargetMapForTesting();
+  return resource_settings;
+}
+
+static ResourceSettings CreateResourceSettings() {
+  return CreateResourceSettings(1);
+}
+
 class TextureStateTrackingContext : public TestWebGraphicsContext3D {
  public:
   MOCK_METHOD2(bindTexture, void(GLenum target, GLuint texture));
@@ -449,18 +467,15 @@
     child_gpu_memory_buffer_manager_ =
         gpu_memory_buffer_manager_->CreateClientGpuMemoryBufferManager();
 
+    ResourceSettings resource_settings = CreateResourceSettings();
     resource_provider_ = base::MakeUnique<ResourceProvider>(
         context_provider_.get(), shared_bitmap_manager_.get(),
-        gpu_memory_buffer_manager_.get(), main_thread_task_runner_.get(), 1,
-        kDelegatedSyncPointsRequired, kUseGpuMemoryBufferResources,
-        kEnableColorCorrectRendering,
-        DefaultBufferToTextureTargetMapForTesting());
+        gpu_memory_buffer_manager_.get(), main_thread_task_runner_.get(),
+        kDelegatedSyncPointsRequired, resource_settings);
     child_resource_provider_ = base::MakeUnique<ResourceProvider>(
         child_context_provider_.get(), shared_bitmap_manager_.get(),
         child_gpu_memory_buffer_manager_.get(), main_thread_task_runner_.get(),
-        1, child_needs_sync_token, kUseGpuMemoryBufferResources,
-        kEnableColorCorrectRendering,
-        DefaultBufferToTextureTargetMapForTesting());
+        child_needs_sync_token, resource_settings);
   }
 
   ResourceProviderTest() : ResourceProviderTest(true) {}
@@ -1627,10 +1642,8 @@
   std::unique_ptr<ResourceProvider> child_resource_provider(
       base::MakeUnique<ResourceProvider>(
           child_context_provider.get(), shared_bitmap_manager_.get(),
-          gpu_memory_buffer_manager_.get(), nullptr, 1,
-          kDelegatedSyncPointsRequired, kUseGpuMemoryBufferResources,
-          kEnableColorCorrectRendering,
-          DefaultBufferToTextureTargetMapForTesting()));
+          gpu_memory_buffer_manager_.get(), nullptr,
+          kDelegatedSyncPointsRequired, CreateResourceSettings()));
 
   gfx::Size size(1, 1);
   ResourceFormat format = RGBA_8888;
@@ -2147,12 +2160,11 @@
     child_context_provider->BindToCurrentThread();
     auto shared_bitmap_manager = base::MakeUnique<TestSharedBitmapManager>();
 
+    ResourceSettings resource_settings = CreateResourceSettings();
     std::unique_ptr<ResourceProvider> child_resource_provider(
         base::MakeUnique<ResourceProvider>(
             child_context_provider.get(), shared_bitmap_manager.get(), nullptr,
-            nullptr, 1, kDelegatedSyncPointsRequired,
-            kUseGpuMemoryBufferResources, kEnableColorCorrectRendering,
-            DefaultBufferToTextureTargetMapForTesting()));
+            nullptr, kDelegatedSyncPointsRequired, resource_settings));
 
     std::unique_ptr<TextureStateTrackingContext> parent_context_owned(
         new TextureStateTrackingContext);
@@ -2165,9 +2177,7 @@
     std::unique_ptr<ResourceProvider> parent_resource_provider(
         base::MakeUnique<ResourceProvider>(
             parent_context_provider.get(), shared_bitmap_manager.get(), nullptr,
-            nullptr, 1, kDelegatedSyncPointsRequired,
-            kUseGpuMemoryBufferResources, kEnableColorCorrectRendering,
-            DefaultBufferToTextureTargetMapForTesting()));
+            nullptr, kDelegatedSyncPointsRequired, resource_settings));
 
     gfx::Size size(1, 1);
     ResourceFormat format = RGBA_8888;
@@ -2802,10 +2812,8 @@
   std::unique_ptr<ResourceProvider> resource_provider(
       base::MakeUnique<ResourceProvider>(
           context_provider.get(), shared_bitmap_manager_.get(),
-          gpu_memory_buffer_manager_.get(), nullptr, 1,
-          kDelegatedSyncPointsRequired, kUseGpuMemoryBufferResources,
-          kEnableColorCorrectRendering,
-          DefaultBufferToTextureTargetMapForTesting()));
+          gpu_memory_buffer_manager_.get(), nullptr,
+          kDelegatedSyncPointsRequired, CreateResourceSettings()));
 
   gfx::Size size(1, 1);
   ResourceFormat format = RGBA_8888;
@@ -2882,10 +2890,8 @@
   std::unique_ptr<ResourceProvider> resource_provider(
       base::MakeUnique<ResourceProvider>(
           context_provider.get(), shared_bitmap_manager_.get(),
-          gpu_memory_buffer_manager_.get(), nullptr, 1,
-          kDelegatedSyncPointsRequired, kUseGpuMemoryBufferResources,
-          kEnableColorCorrectRendering,
-          DefaultBufferToTextureTargetMapForTesting()));
+          gpu_memory_buffer_manager_.get(), nullptr,
+          kDelegatedSyncPointsRequired, CreateResourceSettings()));
 
   gfx::Size size(1, 1);
   ResourceFormat format = RGBA_8888;
@@ -2926,10 +2932,8 @@
   std::unique_ptr<ResourceProvider> resource_provider(
       base::MakeUnique<ResourceProvider>(
           context_provider.get(), shared_bitmap_manager_.get(),
-          gpu_memory_buffer_manager_.get(), nullptr, 1,
-          kDelegatedSyncPointsRequired, kUseGpuMemoryBufferResources,
-          kEnableColorCorrectRendering,
-          DefaultBufferToTextureTargetMapForTesting()));
+          gpu_memory_buffer_manager_.get(), nullptr,
+          kDelegatedSyncPointsRequired, CreateResourceSettings()));
 
   gfx::Size size(1, 1);
   ResourceFormat format = RGBA_8888;
@@ -2971,10 +2975,8 @@
   std::unique_ptr<ResourceProvider> resource_provider(
       base::MakeUnique<ResourceProvider>(
           context_provider.get(), shared_bitmap_manager_.get(),
-          gpu_memory_buffer_manager_.get(), nullptr, 1,
-          kDelegatedSyncPointsRequired, kUseGpuMemoryBufferResources,
-          kEnableColorCorrectRendering,
-          DefaultBufferToTextureTargetMapForTesting()));
+          gpu_memory_buffer_manager_.get(), nullptr,
+          kDelegatedSyncPointsRequired, CreateResourceSettings()));
 
   gfx::Size size(1, 1);
   ResourceFormat format = RGBA_8888;
@@ -3027,10 +3029,8 @@
   std::unique_ptr<ResourceProvider> resource_provider(
       base::MakeUnique<ResourceProvider>(
           nullptr, shared_bitmap_manager_.get(),
-          gpu_memory_buffer_manager_.get(), main_thread_task_runner_.get(), 1,
-          kDelegatedSyncPointsRequired, kUseGpuMemoryBufferResources,
-          kEnableColorCorrectRendering,
-          DefaultBufferToTextureTargetMapForTesting()));
+          gpu_memory_buffer_manager_.get(), main_thread_task_runner_.get(),
+          kDelegatedSyncPointsRequired, CreateResourceSettings()));
 
   gpu::SyncToken release_sync_token;
   bool lost_resource = false;
@@ -3077,10 +3077,8 @@
     std::unique_ptr<ResourceProvider> resource_provider(
         base::MakeUnique<ResourceProvider>(
             context_provider.get(), shared_bitmap_manager,
-            gpu_memory_buffer_manager, main_thread_task_runner, 1,
-            kDelegatedSyncPointsRequired, kUseGpuMemoryBufferResources,
-            kEnableColorCorrectRendering,
-            DefaultBufferToTextureTargetMapForTesting()));
+            gpu_memory_buffer_manager, main_thread_task_runner,
+            kDelegatedSyncPointsRequired, CreateResourceSettings()));
 
     unsigned texture_id = 1;
     gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO, 0,
@@ -3222,10 +3220,8 @@
   std::unique_ptr<ResourceProvider> resource_provider(
       base::MakeUnique<ResourceProvider>(
           context_provider.get(), shared_bitmap_manager_.get(),
-          gpu_memory_buffer_manager_.get(), nullptr, 1,
-          kDelegatedSyncPointsRequired, kUseGpuMemoryBufferResources,
-          kEnableColorCorrectRendering,
-          DefaultBufferToTextureTargetMapForTesting()));
+          gpu_memory_buffer_manager_.get(), nullptr,
+          kDelegatedSyncPointsRequired, CreateResourceSettings()));
 
   gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO, 0,
                             gpu::CommandBufferId::FromUnsafeValue(0x12), 0x34);
@@ -3292,10 +3288,8 @@
   std::unique_ptr<ResourceProvider> resource_provider(
       base::MakeUnique<ResourceProvider>(
           context_provider.get(), shared_bitmap_manager_.get(),
-          gpu_memory_buffer_manager_.get(), nullptr, 1,
-          kDelegatedSyncPointsRequired, kUseGpuMemoryBufferResources,
-          kEnableColorCorrectRendering,
-          DefaultBufferToTextureTargetMapForTesting()));
+          gpu_memory_buffer_manager_.get(), nullptr,
+          kDelegatedSyncPointsRequired, CreateResourceSettings()));
 
   gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO, 0,
                             gpu::CommandBufferId::FromUnsafeValue(0x12), 0x34);
@@ -3348,10 +3342,8 @@
   std::unique_ptr<ResourceProvider> resource_provider(
       base::MakeUnique<ResourceProvider>(
           context_provider.get(), shared_bitmap_manager_.get(),
-          gpu_memory_buffer_manager_.get(), nullptr, 1,
-          kDelegatedSyncPointsRequired, kUseGpuMemoryBufferResources,
-          kEnableColorCorrectRendering,
-          DefaultBufferToTextureTargetMapForTesting()));
+          gpu_memory_buffer_manager_.get(), nullptr,
+          kDelegatedSyncPointsRequired, CreateResourceSettings()));
 
   gpu::SyncToken sync_token;
   const GLuint64 current_fence_sync = context->GetNextFenceSync();
@@ -3470,10 +3462,8 @@
   std::unique_ptr<ResourceProvider> resource_provider(
       base::MakeUnique<ResourceProvider>(
           context_provider.get(), shared_bitmap_manager_.get(),
-          gpu_memory_buffer_manager_.get(), nullptr, 1,
-          kDelegatedSyncPointsRequired, kUseGpuMemoryBufferResources,
-          kEnableColorCorrectRendering,
-          DefaultBufferToTextureTargetMapForTesting()));
+          gpu_memory_buffer_manager_.get(), nullptr,
+          kDelegatedSyncPointsRequired, CreateResourceSettings()));
 
   gfx::Size size(2, 2);
   gfx::Vector2d offset(0, 0);
@@ -3528,10 +3518,8 @@
   std::unique_ptr<ResourceProvider> resource_provider(
       base::MakeUnique<ResourceProvider>(
           context_provider.get(), shared_bitmap_manager_.get(),
-          gpu_memory_buffer_manager_.get(), nullptr, 1,
-          kDelegatedSyncPointsRequired, kUseGpuMemoryBufferResources,
-          kEnableColorCorrectRendering,
-          DefaultBufferToTextureTargetMapForTesting()));
+          gpu_memory_buffer_manager_.get(), nullptr,
+          kDelegatedSyncPointsRequired, CreateResourceSettings()));
 
   gfx::Size size(2, 2);
 
@@ -3584,10 +3572,8 @@
   std::unique_ptr<ResourceProvider> resource_provider(
       base::MakeUnique<ResourceProvider>(
           context_provider.get(), shared_bitmap_manager_.get(),
-          gpu_memory_buffer_manager_.get(), nullptr, 1,
-          kDelegatedSyncPointsRequired, kUseGpuMemoryBufferResources,
-          kEnableColorCorrectRendering,
-          DefaultBufferToTextureTargetMapForTesting()));
+          gpu_memory_buffer_manager_.get(), nullptr,
+          kDelegatedSyncPointsRequired, CreateResourceSettings()));
 
   gfx::Size size(2, 2);
   const ResourceFormat formats[2] = {RGBA_8888, BGRA_8888};
@@ -3643,10 +3629,8 @@
   std::unique_ptr<ResourceProvider> resource_provider(
       base::MakeUnique<ResourceProvider>(
           context_provider.get(), shared_bitmap_manager_.get(),
-          gpu_memory_buffer_manager_.get(), nullptr, 1,
-          kDelegatedSyncPointsRequired, kUseGpuMemoryBufferResources,
-          kEnableColorCorrectRendering,
-          DefaultBufferToTextureTargetMapForTesting()));
+          gpu_memory_buffer_manager_.get(), nullptr,
+          kDelegatedSyncPointsRequired, CreateResourceSettings()));
 
   id = resource_provider->CreateResource(
       size, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format,
@@ -3722,10 +3706,8 @@
   std::unique_ptr<ResourceProvider> resource_provider(
       base::MakeUnique<ResourceProvider>(
           context_provider.get(), shared_bitmap_manager_.get(),
-          gpu_memory_buffer_manager_.get(), nullptr, 1,
-          kDelegatedSyncPointsRequired, kUseGpuMemoryBufferResources,
-          kEnableColorCorrectRendering,
-          DefaultBufferToTextureTargetMapForTesting()));
+          gpu_memory_buffer_manager_.get(), nullptr,
+          kDelegatedSyncPointsRequired, CreateResourceSettings()));
   int texture_id = 123;
 
   ResourceId id = resource_provider->CreateResource(
@@ -3754,10 +3736,8 @@
   std::unique_ptr<ResourceProvider> resource_provider(
       base::MakeUnique<ResourceProvider>(
           context_provider.get(), shared_bitmap_manager_.get(),
-          gpu_memory_buffer_manager_.get(), nullptr, 1,
-          kDelegatedSyncPointsRequired, kUseGpuMemoryBufferResources,
-          kEnableColorCorrectRendering,
-          DefaultBufferToTextureTargetMapForTesting()));
+          gpu_memory_buffer_manager_.get(), nullptr,
+          kDelegatedSyncPointsRequired, CreateResourceSettings()));
   int texture_id = 123;
   uint8_t pixels[8];
 
@@ -3810,9 +3790,8 @@
     std::unique_ptr<ResourceProvider> resource_provider(
         base::MakeUnique<ResourceProvider>(
             context_provider.get(), shared_bitmap_manager.get(), nullptr,
-            nullptr, kTextureAllocationChunkSize, kDelegatedSyncPointsRequired,
-            kUseGpuMemoryBufferResources, kEnableColorCorrectRendering,
-            DefaultBufferToTextureTargetMapForTesting()));
+            nullptr, kDelegatedSyncPointsRequired,
+            CreateResourceSettings(kTextureAllocationChunkSize)));
 
     ResourceId id = resource_provider->CreateResource(
         size, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format,
@@ -3829,9 +3808,8 @@
     std::unique_ptr<ResourceProvider> resource_provider(
         base::MakeUnique<ResourceProvider>(
             context_provider.get(), shared_bitmap_manager.get(), nullptr,
-            nullptr, kTextureAllocationChunkSize, kDelegatedSyncPointsRequired,
-            kUseGpuMemoryBufferResources, kEnableColorCorrectRendering,
-            DefaultBufferToTextureTargetMapForTesting()));
+            nullptr, kDelegatedSyncPointsRequired,
+            CreateResourceSettings(kTextureAllocationChunkSize)));
 
     ResourceId id = resource_provider->CreateResource(
         size, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format,
diff --git a/cc/resources/resource_settings.cc b/cc/resources/resource_settings.cc
new file mode 100644
index 0000000..bd9ce41b5
--- /dev/null
+++ b/cc/resources/resource_settings.cc
@@ -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.
+
+#include "cc/resources/resource_settings.h"
+
+namespace cc {
+
+ResourceSettings::ResourceSettings() = default;
+
+ResourceSettings::ResourceSettings(const ResourceSettings& other) = default;
+
+ResourceSettings::~ResourceSettings() = default;
+
+}  // namespace cc
diff --git a/cc/resources/resource_settings.h b/cc/resources/resource_settings.h
new file mode 100644
index 0000000..a7ab9b69
--- /dev/null
+++ b/cc/resources/resource_settings.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 CC_RESOURCES_RESOURCE_SETTINGS_H_
+#define CC_RESOURCES_RESOURCE_SETTINGS_H_
+
+#include "cc/cc_export.h"
+#include "cc/output/buffer_to_texture_target_map.h"
+
+namespace cc {
+
+// ResourceSettings contains all the settings that are needed to create a
+// ResourceProvider.
+class CC_EXPORT ResourceSettings {
+ public:
+  ResourceSettings();
+  ResourceSettings(const ResourceSettings& other);
+  ~ResourceSettings();
+
+  size_t texture_id_allocation_chunk_size = 64;
+  bool use_gpu_memory_buffer_resources = false;
+  bool enable_color_correct_rasterization = false;
+  BufferToTextureTargetMap buffer_to_texture_target_map;
+};
+
+}  // namespace cc
+
+#endif  // CC_RESOURCES_RESOURCE_SETTINGS_H_
diff --git a/cc/surfaces/display.cc b/cc/surfaces/display.cc
index a46731ff..586b9c2 100644
--- a/cc/surfaces/display.cc
+++ b/cc/surfaces/display.cc
@@ -184,13 +184,11 @@
 
 void Display::InitializeRenderer() {
   // Not relevant for display compositor since it's not delegated.
-  bool delegated_sync_points_required = false;
+  constexpr bool delegated_sync_points_required = false;
   resource_provider_.reset(new ResourceProvider(
       output_surface_->context_provider(), bitmap_manager_,
-      gpu_memory_buffer_manager_, nullptr,
-      settings_.texture_id_allocation_chunk_size,
-      delegated_sync_points_required, settings_.use_gpu_memory_buffer_resources,
-      false, settings_.buffer_to_texture_target_map));
+      gpu_memory_buffer_manager_, nullptr, delegated_sync_points_required,
+      settings_.resource_settings));
 
   if (output_surface_->context_provider()) {
     DCHECK(texture_mailbox_deleter_);
diff --git a/cc/test/fake_layer_tree_host_impl_client.h b/cc/test/fake_layer_tree_host_impl_client.h
index 4dd405d..2006d5d4 100644
--- a/cc/test/fake_layer_tree_host_impl_client.h
+++ b/cc/test/fake_layer_tree_host_impl_client.h
@@ -36,6 +36,7 @@
   void DidCompletePageScaleAnimationOnImplThread() override {}
   void OnDrawForCompositorFrameSink(bool resourceless_software_draw) override {}
   void NeedsImplSideInvalidation() override;
+  void NotifyImageDecodeRequestFinished() override {}
 
   void reset_did_request_impl_side_invalidation() {
     did_request_impl_side_invalidation_ = false;
diff --git a/cc/test/fake_resource_provider.h b/cc/test/fake_resource_provider.h
index c40850d..e092031 100644
--- a/cc/test/fake_resource_provider.h
+++ b/cc/test/fake_resource_provider.h
@@ -9,7 +9,6 @@
 
 #include "base/memory/ptr_util.h"
 #include "cc/output/buffer_to_texture_target_map.h"
-#include "cc/output/renderer_settings.h"
 #include "cc/resources/resource_provider.h"
 #include "ui/gfx/buffer_types.h"
 
@@ -20,41 +19,41 @@
   static std::unique_ptr<FakeResourceProvider> Create(
       ContextProvider* context_provider,
       SharedBitmapManager* shared_bitmap_manager) {
-    return base::WrapUnique(new FakeResourceProvider(
-        context_provider, shared_bitmap_manager, nullptr, nullptr, 1, true,
-        false, false, DefaultBufferToTextureTargetMapForTesting()));
+    ResourceSettings resource_settings;
+    resource_settings.texture_id_allocation_chunk_size = 1;
+    resource_settings.buffer_to_texture_target_map =
+        DefaultBufferToTextureTargetMapForTesting();
+    return base::WrapUnique(
+        new FakeResourceProvider(context_provider, shared_bitmap_manager,
+                                 nullptr, nullptr, true, resource_settings));
   }
 
   static std::unique_ptr<FakeResourceProvider> Create(
       ContextProvider* context_provider,
       SharedBitmapManager* shared_bitmap_manager,
       gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager) {
+    ResourceSettings resource_settings;
+    resource_settings.texture_id_allocation_chunk_size = 1;
+    resource_settings.buffer_to_texture_target_map =
+        DefaultBufferToTextureTargetMapForTesting();
     return base::WrapUnique(new FakeResourceProvider(
         context_provider, shared_bitmap_manager, gpu_memory_buffer_manager,
-        nullptr, 1, true, false, false,
-        DefaultBufferToTextureTargetMapForTesting()));
+        nullptr, true, resource_settings));
   }
 
  private:
-  FakeResourceProvider(
-      ContextProvider* context_provider,
-      SharedBitmapManager* shared_bitmap_manager,
-      gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
-      BlockingTaskRunner* blocking_main_thread_task_runner,
-      size_t id_allocation_chunk_size,
-      bool delegated_sync_points_required,
-      bool use_gpu_memory_buffer_resources,
-      bool enable_color_correct_rendering,
-      const BufferToTextureTargetMap& buffer_to_texture_target_map)
+  FakeResourceProvider(ContextProvider* context_provider,
+                       SharedBitmapManager* shared_bitmap_manager,
+                       gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
+                       BlockingTaskRunner* blocking_main_thread_task_runner,
+                       bool delegated_sync_points_required,
+                       const ResourceSettings resource_settings)
       : ResourceProvider(context_provider,
                          shared_bitmap_manager,
                          gpu_memory_buffer_manager,
                          blocking_main_thread_task_runner,
-                         id_allocation_chunk_size,
                          delegated_sync_points_required,
-                         use_gpu_memory_buffer_resources,
-                         enable_color_correct_rendering,
-                         buffer_to_texture_target_map) {}
+                         resource_settings) {}
 };
 
 }  // namespace cc
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index 6e18025..ddf318c5 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -829,7 +829,7 @@
   // Disable latency recovery to make the scheduler more predictable in its
   // actions and less dependent on timings to make decisions.
   settings_.enable_latency_recovery = false;
-  settings_.buffer_to_texture_target_map =
+  settings_.resource_settings.buffer_to_texture_target_map =
       DefaultBufferToTextureTargetMapForTesting();
   InitializeSettings(&settings_);
 
@@ -858,8 +858,10 @@
       TestContextProvider::CreateWorker();
 
   RendererSettings renderer_settings;
+  // Spend less time waiting for BeginFrame because the output is
+  // mocked out.
   renderer_settings.refresh_rate = 200.0;
-  renderer_settings.buffer_to_texture_target_map =
+  renderer_settings.resource_settings.buffer_to_texture_target_map =
       DefaultBufferToTextureTargetMapForTesting();
   auto compositor_frame_sink = CreateCompositorFrameSink(
       renderer_settings, std::move(shared_context_provider),
diff --git a/cc/test/pixel_test.cc b/cc/test/pixel_test.cc
index 31898ab..f0482a7 100644
--- a/cc/test/pixel_test.cc
+++ b/cc/test/pixel_test.cc
@@ -39,8 +39,7 @@
       disable_picture_quad_image_filtering_(false),
       output_surface_client_(new FakeOutputSurfaceClient),
       main_thread_task_runner_(
-          BlockingTaskRunner::Create(base::ThreadTaskRunnerHandle::Get())) {
-}
+          BlockingTaskRunner::Create(base::ThreadTaskRunnerHandle::Get())) {}
 PixelTest::~PixelTest() {}
 
 bool PixelTest::RunPixelTest(RenderPassList* pass_list,
@@ -167,14 +166,11 @@
   shared_bitmap_manager_.reset(new TestSharedBitmapManager);
   gpu_memory_buffer_manager_.reset(new TestGpuMemoryBufferManager);
   // Not relevant for display compositor since it's not delegated.
-  bool delegated_sync_points_required = false;
+  constexpr bool delegated_sync_points_required = false;
   resource_provider_ = base::MakeUnique<ResourceProvider>(
       output_surface_->context_provider(), shared_bitmap_manager_.get(),
-      gpu_memory_buffer_manager_.get(), main_thread_task_runner_.get(), 1,
-      delegated_sync_points_required,
-      settings_.renderer_settings.use_gpu_memory_buffer_resources,
-      settings_.enable_color_correct_rasterization,
-      settings_.buffer_to_texture_target_map);
+      gpu_memory_buffer_manager_.get(), main_thread_task_runner_.get(),
+      delegated_sync_points_required, settings_.resource_settings);
 
   texture_mailbox_deleter_ = base::MakeUnique<TextureMailboxDeleter>(
       base::ThreadTaskRunnerHandle::Get());
@@ -196,13 +192,12 @@
       new PixelTestOutputSurface(base::MakeUnique<SoftwareOutputDevice>()));
   output_surface_->BindToClient(output_surface_client_.get());
   shared_bitmap_manager_.reset(new TestSharedBitmapManager());
-  bool delegated_sync_points_required = false;  // Meaningless for software.
+  constexpr bool delegated_sync_points_required =
+      false;  // Meaningless for software.
   resource_provider_ = base::MakeUnique<ResourceProvider>(
       nullptr, shared_bitmap_manager_.get(), gpu_memory_buffer_manager_.get(),
-      main_thread_task_runner_.get(), 1, delegated_sync_points_required,
-      settings_.renderer_settings.use_gpu_memory_buffer_resources,
-      settings_.enable_color_correct_rasterization,
-      settings_.buffer_to_texture_target_map);
+      main_thread_task_runner_.get(), delegated_sync_points_required,
+      settings_.resource_settings);
   auto renderer = base::MakeUnique<SoftwareRenderer>(
       &settings_.renderer_settings, output_surface_.get(),
       resource_provider_.get());
diff --git a/cc/tiles/tile_manager_unittest.cc b/cc/tiles/tile_manager_unittest.cc
index 3b61ba6..d36a7824 100644
--- a/cc/tiles/tile_manager_unittest.cc
+++ b/cc/tiles/tile_manager_unittest.cc
@@ -87,7 +87,7 @@
   LayerTreeSettings CreateSettings() override {
     LayerTreeSettings settings;
     settings.create_low_res_tiling = true;
-    settings.buffer_to_texture_target_map =
+    settings.resource_settings.buffer_to_texture_target_map =
         DefaultBufferToTextureTargetMapForTesting();
     return settings;
   }
@@ -2055,7 +2055,7 @@
 
   LayerTreeSettings CreateSettings() override {
     LayerTreeSettings settings;
-    settings.buffer_to_texture_target_map =
+    settings.resource_settings.buffer_to_texture_target_map =
         DefaultBufferToTextureTargetMapForTesting();
     return settings;
   }
@@ -2334,7 +2334,7 @@
   LayerTreeSettings CreateSettings() override {
     LayerTreeSettings settings;
     settings.enable_checker_imaging = true;
-    settings.buffer_to_texture_target_map =
+    settings.resource_settings.buffer_to_texture_target_map =
         DefaultBufferToTextureTargetMapForTesting();
     return settings;
   }
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index fbe68d2..82ffc72 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -2380,7 +2380,7 @@
     bool decode_succeeded) {
   completed_image_decode_callbacks_.emplace_back(
       base::Bind(embedder_callback, decode_succeeded));
-  client_->SetNeedsCommitOnImplThread();
+  client_->NotifyImageDecodeRequestFinished();
 }
 
 std::vector<base::Closure>
@@ -2486,11 +2486,8 @@
       compositor_frame_sink_->shared_bitmap_manager(),
       compositor_frame_sink_->gpu_memory_buffer_manager(),
       task_runner_provider_->blocking_main_thread_task_runner(),
-      settings_.renderer_settings.texture_id_allocation_chunk_size,
       compositor_frame_sink_->capabilities().delegated_sync_points_required,
-      settings_.renderer_settings.use_gpu_memory_buffer_resources,
-      settings_.enable_color_correct_rasterization,
-      settings_.buffer_to_texture_target_map);
+      settings_.resource_settings);
 
   // Since the new context may be capable of MSAA, update status here. We don't
   // need to check the return value since we are recreating all resources
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index b8553cb..3036110 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -128,6 +128,8 @@
       bool resourceless_software_draw) = 0;
 
   virtual void NeedsImplSideInvalidation() = 0;
+  // Called when a requested image decode completes.
+  virtual void NotifyImageDecodeRequestFinished() = 0;
 
  protected:
   virtual ~LayerTreeHostImplClient() {}
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index d90ce99..6d4c8d1 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -130,8 +130,8 @@
     LayerTreeSettings settings;
     settings.enable_surface_synchronization = true;
     settings.minimum_occlusion_tracking_size = gfx::Size();
-    settings.renderer_settings.texture_id_allocation_chunk_size = 1;
-    settings.buffer_to_texture_target_map =
+    settings.resource_settings.texture_id_allocation_chunk_size = 1;
+    settings.resource_settings.buffer_to_texture_target_map =
         DefaultBufferToTextureTargetMapForTesting();
     return settings;
   }
@@ -192,6 +192,7 @@
   void NeedsImplSideInvalidation() override {
     did_request_impl_side_invalidation_ = true;
   }
+  void NotifyImageDecodeRequestFinished() override {}
 
   void set_reduce_memory_result(bool reduce_memory_result) {
     reduce_memory_result_ = reduce_memory_result;
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index b74965d..9a7e2f9 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -3461,7 +3461,7 @@
   LayerTreeHostTestUIResource() : num_ui_resources_(0) {}
 
   void InitializeSettings(LayerTreeSettings* settings) override {
-    settings->renderer_settings.texture_id_allocation_chunk_size = 1;
+    settings->resource_settings.texture_id_allocation_chunk_size = 1;
   }
 
   void BeginTest() override { PostSetNeedsCommitToMainThread(); }
diff --git a/cc/trees/layer_tree_host_unittest_context.cc b/cc/trees/layer_tree_host_unittest_context.cc
index 1c630f04..c3584d3 100644
--- a/cc/trees/layer_tree_host_unittest_context.cc
+++ b/cc/trees/layer_tree_host_unittest_context.cc
@@ -1133,7 +1133,7 @@
  public:
   UIResourceLostTest() : time_step_(0) {}
   void InitializeSettings(LayerTreeSettings* settings) override {
-    settings->renderer_settings.texture_id_allocation_chunk_size = 1;
+    settings->resource_settings.texture_id_allocation_chunk_size = 1;
   }
   void BeginTest() override { PostSetNeedsCommitToMainThread(); }
   void AfterTest() override {}
diff --git a/cc/trees/layer_tree_host_unittest_copyrequest.cc b/cc/trees/layer_tree_host_unittest_copyrequest.cc
index a29453c..4bb4aafe 100644
--- a/cc/trees/layer_tree_host_unittest_copyrequest.cc
+++ b/cc/trees/layer_tree_host_unittest_copyrequest.cc
@@ -860,7 +860,7 @@
  protected:
   void InitializeSettings(LayerTreeSettings* settings) override {
     // Always allocate only a single texture at a time through ResourceProvider.
-    settings->renderer_settings.texture_id_allocation_chunk_size = 1;
+    settings->resource_settings.texture_id_allocation_chunk_size = 1;
   }
 
   std::unique_ptr<OutputSurface> CreateDisplayOutputSurfaceOnThread(
diff --git a/cc/trees/layer_tree_settings.h b/cc/trees/layer_tree_settings.h
index 63eb99f..ed16071 100644
--- a/cc/trees/layer_tree_settings.h
+++ b/cc/trees/layer_tree_settings.h
@@ -15,6 +15,7 @@
 #include "cc/output/managed_memory_policy.h"
 #include "cc/output/renderer_settings.h"
 #include "cc/resources/resource_format.h"
+#include "cc/resources/resource_settings.h"
 #include "cc/scheduler/scheduler_settings.h"
 #include "cc/tiles/tile_manager_settings.h"
 #include "third_party/skia/include/core/SkColor.h"
@@ -32,6 +33,7 @@
   TileManagerSettings ToTileManagerSettings() const;
 
   RendererSettings renderer_settings;
+  ResourceSettings resource_settings;
   bool single_thread_proxy_scheduler = true;
   bool main_frame_before_activation_enabled = false;
   bool using_synchronous_renderer_compositor = false;
@@ -87,7 +89,6 @@
   size_t decoded_image_cache_budget_bytes = 128 * 1024 * 1024;
   size_t decoded_image_working_set_budget_bytes = 128 * 1024 * 1024;
   int max_preraster_distance_in_screen_pixels = 1000;
-  BufferToTextureTargetMap buffer_to_texture_target_map;
   ResourceFormat preferred_tile_format;
 
   bool enable_color_correct_rasterization = false;
diff --git a/cc/trees/proxy_impl.cc b/cc/trees/proxy_impl.cc
index 01a96109c..8ef7061 100644
--- a/cc/trees/proxy_impl.cc
+++ b/cc/trees/proxy_impl.cc
@@ -473,6 +473,11 @@
   scheduler_->SetNeedsImplSideInvalidation();
 }
 
+void ProxyImpl::NotifyImageDecodeRequestFinished() {
+  DCHECK(IsImplThread());
+  SetNeedsCommitOnImplThread();
+}
+
 void ProxyImpl::WillBeginImplFrame(const BeginFrameArgs& args) {
   DCHECK(IsImplThread());
   layer_tree_host_impl_->WillBeginImplFrame(args);
diff --git a/cc/trees/proxy_impl.h b/cc/trees/proxy_impl.h
index 0953ae7..92639a0 100644
--- a/cc/trees/proxy_impl.h
+++ b/cc/trees/proxy_impl.h
@@ -94,6 +94,7 @@
   void DidCompletePageScaleAnimationOnImplThread() override;
   void OnDrawForCompositorFrameSink(bool resourceless_software_draw) override;
   void NeedsImplSideInvalidation() override;
+  void NotifyImageDecodeRequestFinished() override;
 
   // SchedulerClient implementation
   void WillBeginImplFrame(const BeginFrameArgs& args) override;
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc
index 1769c19..7dc16da47 100644
--- a/cc/trees/single_thread_proxy.cc
+++ b/cc/trees/single_thread_proxy.cc
@@ -207,12 +207,7 @@
     if (scheduler_on_impl_thread_)
       scheduler_on_impl_thread_->DidCommit();
 
-    // Issue decode callbacks.
-    auto completed_decode_callbacks =
-        layer_tree_host_impl_->TakeCompletedImageDecodeCallbacks();
-    for (auto& callback : completed_decode_callbacks)
-      callback.Run();
-
+    IssueImageDecodeFinishedCallbacks();
     layer_tree_host_impl_->CommitComplete();
 
     // Commit goes directly to the active tree, but we need to synchronously
@@ -224,6 +219,15 @@
   }
 }
 
+void SingleThreadProxy::IssueImageDecodeFinishedCallbacks() {
+  DCHECK(task_runner_provider_->IsImplThread());
+
+  auto completed_decode_callbacks =
+      layer_tree_host_impl_->TakeCompletedImageDecodeCallbacks();
+  for (auto& callback : completed_decode_callbacks)
+    callback.Run();
+}
+
 void SingleThreadProxy::CommitComplete() {
   // Commit complete happens on the main side after activate to satisfy any
   // SetNextCommitWaitsForActivation calls.
@@ -446,6 +450,19 @@
   scheduler_on_impl_thread_->SetNeedsImplSideInvalidation();
 }
 
+void SingleThreadProxy::NotifyImageDecodeRequestFinished() {
+  // If we don't have a scheduler, then just issue the callbacks here.
+  // Otherwise, schedule a commit.
+  if (!scheduler_on_impl_thread_) {
+    DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_);
+    DebugScopedSetImplThread impl(task_runner_provider_);
+
+    IssueImageDecodeFinishedCallbacks();
+    return;
+  }
+  SetNeedsCommitOnImplThread();
+}
+
 void SingleThreadProxy::CompositeImmediately(base::TimeTicks frame_begin_time) {
   TRACE_EVENT0("cc,benchmark", "SingleThreadProxy::CompositeImmediately");
   DCHECK(task_runner_provider_->IsMainThread());
diff --git a/cc/trees/single_thread_proxy.h b/cc/trees/single_thread_proxy.h
index 54842c41..4ff0075 100644
--- a/cc/trees/single_thread_proxy.h
+++ b/cc/trees/single_thread_proxy.h
@@ -100,6 +100,7 @@
   void DidCompletePageScaleAnimationOnImplThread() override;
   void OnDrawForCompositorFrameSink(bool resourceless_software_draw) override;
   void NeedsImplSideInvalidation() override;
+  void NotifyImageDecodeRequestFinished() override;
 
   void RequestNewCompositorFrameSink();
 
@@ -124,6 +125,7 @@
 
   bool ShouldComposite() const;
   void ScheduleRequestNewCompositorFrameSink();
+  void IssueImageDecodeFinishedCallbacks();
 
   void DidReceiveCompositorFrameAck();
 
diff --git a/chrome/android/java/res/drawable/btn_reload_stop.xml b/chrome/android/java/res/drawable/btn_reload_stop.xml
index bc32d56..288a79f 100644
--- a/chrome/android/java/res/drawable/btn_reload_stop.xml
+++ b/chrome/android/java/res/drawable/btn_reload_stop.xml
@@ -4,6 +4,10 @@
      found in the LICENSE file. -->
 
 <level-list xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:maxLevel="0" android:drawable="@drawable/btn_toolbar_reload" />
-    <item android:maxLevel="1" android:drawable="@drawable/btn_close" />
+    <item
+        android:maxLevel="@integer/reload_button_level_reload"
+        android:drawable="@drawable/btn_toolbar_reload" />
+    <item
+        android:maxLevel="@integer/reload_button_level_stop"
+        android:drawable="@drawable/btn_close" />
 </level-list>
\ No newline at end of file
diff --git a/chrome/android/java/res/layout/toolbar_tablet.xml b/chrome/android/java/res/layout/toolbar_tablet.xml
index 458c337..da09ca5b 100644
--- a/chrome/android/java/res/layout/toolbar_tablet.xml
+++ b/chrome/android/java/res/layout/toolbar_tablet.xml
@@ -42,7 +42,7 @@
         <org.chromium.chrome.browser.widget.TintedImageButton
             android:id="@+id/refresh_button"
             style="@style/ToolbarButton"
-            android:src="@drawable/btn_toolbar_reload"
+            android:src="@drawable/btn_reload_stop"
             android:contentDescription="@string/accessibility_btn_refresh" />
 
         <org.chromium.chrome.browser.omnibox.LocationBarTablet
diff --git a/chrome/android/java/res/values/values.xml b/chrome/android/java/res/values/values.xml
index b18d664..ef5aa31 100644
--- a/chrome/android/java/res/values/values.xml
+++ b/chrome/android/java/res/values/values.xml
@@ -38,6 +38,10 @@
     <!-- TabSwitcher - Maximum amount to tilt tabs in over scroll in degrees. -->
     <integer name="over_scroll_angle">15</integer>
 
+    <!-- Toolbar/AppMenu - Drawable level on reload image button -->
+    <integer name="reload_button_level_reload">0</integer>
+    <integer name="reload_button_level_stop">1</integer>
+
     <!-- Help and Feedback
          These constants should be in sync with the context names on go/mobilehelprecs.
          If the context ID cannot be found, the default help page will be shown to the user.-->
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java
index aca842d..a2b232b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java
@@ -401,7 +401,10 @@
         } else if (itemId == R.id.info_menu_id) {
             description = resources.getString(R.string.menu_page_info);
         } else if (itemId == R.id.reload_menu_id) {
-            description = resources.getString(R.string.menu_refresh);
+            description = (menuItem.getIcon().getLevel()
+                                  == resources.getInteger(R.integer.reload_button_level_reload))
+                    ? resources.getString(R.string.menu_refresh)
+                    : resources.getString(R.string.menu_stop_refresh);
         }
         return AccessibilityUtil.showAccessibilityToast(context, view, description);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuIconRowFooter.java b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuIconRowFooter.java
index a471483..7489e4e2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuIconRowFooter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuIconRowFooter.java
@@ -106,7 +106,10 @@
         } else if (itemId == R.id.info_menu_id) {
             description = resources.getString(R.string.menu_page_info);
         } else if (itemId == R.id.reload_menu_id) {
-            description = resources.getString(R.string.menu_refresh);
+            description = (mReloadButton.getDrawable().getLevel()
+                                  == resources.getInteger(R.integer.reload_button_level_reload))
+                    ? resources.getString(R.string.menu_refresh)
+                    : resources.getString(R.string.menu_stop_refresh);
         }
         return AccessibilityUtil.showAccessibilityToast(context, v, description);
     }
@@ -117,8 +120,8 @@
      */
     public void loadingStateChanged(boolean isLoading) {
         mReloadButton.getDrawable().setLevel(isLoading
-                        ? AppMenuPropertiesDelegate.RELOAD_BUTTON_LEVEL_STOP_LOADING
-                        : AppMenuPropertiesDelegate.RELOAD_BUTTON_LEVEL_RELOAD);
+                        ? getResources().getInteger(R.integer.reload_button_level_stop)
+                        : getResources().getInteger(R.integer.reload_button_level_reload));
         mReloadButton.setContentDescription(isLoading
                         ? mActivity.getString(R.string.accessibility_btn_stop_loading)
                         : mActivity.getString(R.string.accessibility_btn_refresh));
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java
index 2abb265..6a008172 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java
@@ -6,6 +6,7 @@
 
 import android.content.Context;
 import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
 import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
 import android.os.SystemClock;
@@ -43,12 +44,6 @@
  * App Menu helper that handles hiding and showing menu items based on activity state.
  */
 public class AppMenuPropertiesDelegate {
-    // Indices for different levels in drawable.btn_reload_stop.
-    // Used only when preparing menu and refresh reload button in menu when tab
-    // page load status changes.
-    static final int RELOAD_BUTTON_LEVEL_RELOAD = 0;
-    static final int RELOAD_BUTTON_LEVEL_STOP_LOADING = 1;
-
     protected MenuItem mReloadMenuItem;
 
     protected final ChromeActivity mActivity;
@@ -291,8 +286,10 @@
      */
     public void loadingStateChanged(boolean isLoading) {
         if (mReloadMenuItem != null) {
+            Resources resources = mActivity.getResources();
             mReloadMenuItem.getIcon().setLevel(isLoading
-                    ? RELOAD_BUTTON_LEVEL_STOP_LOADING : RELOAD_BUTTON_LEVEL_RELOAD);
+                            ? resources.getInteger(R.integer.reload_button_level_stop)
+                            : resources.getInteger(R.integer.reload_button_level_reload));
             mReloadMenuItem.setTitle(isLoading
                     ? R.string.accessibility_btn_stop_loading : R.string.accessibility_btn_refresh);
         } else if (mAppMenuIconRowFooter != null) {
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 73adaac..0a02312a 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
@@ -221,7 +221,6 @@
     @VisibleForTesting
     protected DownloadManagerService(Context context, DownloadNotifier downloadNotifier,
             Handler handler, long updateDelayInMillis) {
-        // TODO(wnwen): Remove mContext since it is always the application context.
         mContext = context;
         mSharedPrefs = ContextUtils.getAppSharedPreferences();
         // Clean up unused shared prefs. TODO(qinmin): remove this after M61.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountManagementFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountManagementFragment.java
index a1fafb5f..74f96a6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountManagementFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountManagementFragment.java
@@ -54,6 +54,7 @@
 import org.chromium.chrome.browser.sync.ProfileSyncService;
 import org.chromium.chrome.browser.sync.ProfileSyncService.SyncStateChangedListener;
 import org.chromium.chrome.browser.sync.ui.SyncCustomizationFragment;
+import org.chromium.chrome.browser.util.IntentUtils;
 import org.chromium.components.signin.AccountManagerHelper;
 import org.chromium.components.signin.ChromeSigninController;
 
@@ -115,6 +116,9 @@
     public static final String PREF_SIGN_OUT = "sign_out";
     public static final String PREF_SIGN_OUT_DIVIDER = "sign_out_divider";
 
+    private static final String ACCOUNT_SETTINGS_ACTION = "android.settings.ACCOUNT_SYNC_SETTINGS";
+    private static final String ACCOUNT_SETTINGS_ACCOUNT_KEY = "account";
+
     private int mGaiaServiceType;
 
     private ArrayList<Preference> mAccountsListPreferences = new ArrayList<>();
@@ -424,13 +428,11 @@
         }
         mAccountsListPreferences.clear();
 
-        final Preferences activity = (Preferences) getActivity();
         Account[] accounts = AccountManagerHelper.get().getGoogleAccounts();
         int nextPrefOrder = FIRST_ACCOUNT_PREF_ORDER;
 
-        for (Account account : accounts) {
-            ChromeBasePreference pref = new ChromeBasePreference(activity);
-            pref.setSelectable(false);
+        for (final Account account : accounts) {
+            ChromeBasePreference pref = new ChromeBasePreference(getActivity());
             pref.setTitle(account.name);
 
             boolean isChildAccount = mProfile.isChild();
@@ -439,6 +441,15 @@
                     isChildAccount ? getBadgedUserPicture(account.name, getResources()) :
                         getUserPicture(account.name, getResources())));
 
+            pref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
+                @Override
+                public boolean onPreferenceClick(Preference preference) {
+                    Intent intent = new Intent(ACCOUNT_SETTINGS_ACTION);
+                    intent.putExtra(ACCOUNT_SETTINGS_ACCOUNT_KEY, account);
+                    return IntentUtils.safeStartActivity(getActivity(), intent);
+                }
+            });
+
             pref.setOrder(nextPrefOrder++);
             prefScreen.addPreference(pref);
             mAccountsListPreferences.add(pref);
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 70dd58c8..4adb903 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
@@ -331,7 +331,10 @@
         Resources resources = context.getResources();
 
         if (v == mReloadButton) {
-            description = resources.getString(R.string.menu_refresh);
+            description = (mReloadButton.getDrawable().getLevel()
+                                  == resources.getInteger(R.integer.reload_button_level_reload))
+                    ? resources.getString(R.string.menu_refresh)
+                    : resources.getString(R.string.menu_stop_refresh);
         } else if (v == mBookmarkButton) {
             description = resources.getString(R.string.menu_bookmark);
         } else if (v == mSaveOfflineButton) {
@@ -439,11 +442,13 @@
     @Override
     protected void updateReloadButtonVisibility(boolean isReloading) {
         if (isReloading) {
-            mReloadButton.setImageResource(R.drawable.btn_close);
+            mReloadButton.getDrawable().setLevel(
+                    getResources().getInteger(R.integer.reload_button_level_stop));
             mReloadButton.setContentDescription(getContext().getString(
                     R.string.accessibility_btn_stop_loading));
         } else {
-            mReloadButton.setImageResource(R.drawable.btn_toolbar_reload);
+            mReloadButton.getDrawable().setLevel(
+                    getResources().getInteger(R.integer.reload_button_level_reload));
             mReloadButton.setContentDescription(getContext().getString(
                     R.string.accessibility_btn_refresh));
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInfo.java
index 76cd867..2dc9ce5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInfo.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInfo.java
@@ -32,6 +32,7 @@
     private static final String TAG = "WebApkInfo";
 
     private boolean mForceNavigation;
+    private Icon mBadgeIcon;
     private String mWebApkPackageName;
     private int mShellApkVersion;
     private String mManifestUrl;
@@ -108,13 +109,16 @@
         String manifestStartUrl = IntentUtils.safeGetString(bundle, WebApkMetaDataKeys.START_URL);
         Map<String, String> iconUrlToMurmur2HashMap = getIconUrlAndIconMurmur2HashMap(bundle);
 
-        int iconId = IntentUtils.safeGetInt(bundle, WebApkMetaDataKeys.ICON_ID, 0);
-        Bitmap icon = decodeImageResource(webApkPackageName, iconId);
+        int primaryIconId = IntentUtils.safeGetInt(bundle, WebApkMetaDataKeys.ICON_ID, 0);
+        Bitmap primaryIcon = decodeImageResource(webApkPackageName, primaryIconId);
+
+        int badgeIconId = IntentUtils.safeGetInt(bundle, WebApkMetaDataKeys.BADGE_ICON_ID, 0);
+        Bitmap badgeIcon = decodeImageResource(webApkPackageName, badgeIconId);
 
         return create(WebApkConstants.WEBAPK_ID_PREFIX + webApkPackageName, url, forceNavigation,
-                scope, new Icon(icon), name, shortName, displayMode, orientation, source,
-                themeColor, backgroundColor, webApkPackageName, shellApkVersion, manifestUrl,
-                manifestStartUrl, iconUrlToMurmur2HashMap);
+                scope, new Icon(primaryIcon), new Icon(badgeIcon), name, shortName, displayMode,
+                orientation, source, themeColor, backgroundColor, webApkPackageName,
+                shellApkVersion, manifestUrl, manifestStartUrl, iconUrlToMurmur2HashMap);
     }
 
     /**
@@ -125,7 +129,8 @@
      * @param forceNavigation         Whether the WebAPK should navigate to {@link url} if the
      *                                WebAPK is already open.
      * @param scope                   Scope for the WebAPK.
-     * @param icon                    Icon to show for the WebAPK.
+     * @param primaryIcon             Primary icon to show for the WebAPK.
+     * @param badgeIcon               Badge icon to use for notifications.
      * @param name                    Name of the WebAPK.
      * @param shortName               The short name of the WebAPK.
      * @param displayMode             Display mode of the WebAPK.
@@ -143,10 +148,10 @@
      *                                icon untransformed bytes.
      */
     public static WebApkInfo create(String id, String url, boolean forceNavigation, String scope,
-            Icon icon, String name, String shortName, int displayMode, int orientation, int source,
-            long themeColor, long backgroundColor, String webApkPackageName, int shellApkVersion,
-            String manifestUrl, String manifestStartUrl,
-            Map<String, String> iconUrlToMurmur2HashMap) {
+            Icon primaryIcon, Icon badgeIcon, String name, String shortName, int displayMode,
+            int orientation, int source, long themeColor, long backgroundColor,
+            String webApkPackageName, int shellApkVersion, String manifestUrl,
+            String manifestStartUrl, Map<String, String> iconUrlToMurmur2HashMap) {
         if (id == null || url == null || manifestStartUrl == null || webApkPackageName == null) {
             Log.e(TAG,
                     "Incomplete data provided: " + id + ", " + url + ", " + manifestStartUrl + ", "
@@ -161,19 +166,22 @@
             scope = ShortcutHelper.getScopeFromUrl(manifestStartUrl);
         }
 
-        return new WebApkInfo(id, url, forceNavigation, scope, icon, name, shortName, displayMode,
-                orientation, source, themeColor, backgroundColor, webApkPackageName,
-                shellApkVersion, manifestUrl, manifestStartUrl, iconUrlToMurmur2HashMap);
+        return new WebApkInfo(id, url, forceNavigation, scope, primaryIcon, badgeIcon, name,
+                shortName, displayMode, orientation, source, themeColor, backgroundColor,
+                webApkPackageName, shellApkVersion, manifestUrl, manifestStartUrl,
+                iconUrlToMurmur2HashMap);
     }
 
-    protected WebApkInfo(String id, String url, boolean forceNavigation, String scope, Icon icon,
-            String name, String shortName, int displayMode, int orientation, int source,
-            long themeColor, long backgroundColor, String webApkPackageName, int shellApkVersion,
-            String manifestUrl, String manifestStartUrl,
-            Map<String, String> iconUrlToMurmur2HashMap) {
-        super(id, url, scope, icon, name, shortName, displayMode, orientation, source, themeColor,
+    protected WebApkInfo(String id, String url, boolean forceNavigation, String scope,
+            Icon primaryIcon, Icon badgeIcon, String name, String shortName, int displayMode,
+            int orientation, int source, long themeColor, long backgroundColor,
+            String webApkPackageName, int shellApkVersion, String manifestUrl,
+            String manifestStartUrl, Map<String, String> iconUrlToMurmur2HashMap) {
+        super(id, url, scope, primaryIcon, name, shortName, displayMode, orientation, source,
+                themeColor,
                 backgroundColor, false);
         mForceNavigation = forceNavigation;
+        mBadgeIcon = badgeIcon;
         mWebApkPackageName = webApkPackageName;
         mShellApkVersion = shellApkVersion;
         mManifestUrl = manifestUrl;
@@ -188,6 +196,13 @@
         return mForceNavigation;
     }
 
+    /**
+     * Returns the badge icon in Bitmap form.
+     */
+    public Bitmap badgeIcon() {
+        return (mBadgeIcon == null) ? null : mBadgeIcon.decoded();
+    }
+
     @Override
     public String webApkPackageName() {
         return mWebApkPackageName;
@@ -234,7 +249,9 @@
         }
     }
 
-    /** Decodes bitmap from WebAPK's resources. */
+    /**
+     * Decodes bitmap from WebAPK's resources. Returns null when resource is not found.
+     */
     private static Bitmap decodeImageResource(String webApkPackageName, int resourceId) {
         PackageManager packageManager = ContextUtils.getApplicationContext().getPackageManager();
         try {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateDataFetcher.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateDataFetcher.java
index 671b45bf..c267b53 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateDataFetcher.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateDataFetcher.java
@@ -99,21 +99,23 @@
      */
     @CalledByNative
     protected void onDataAvailable(String manifestStartUrl, String scopeUrl, String name,
-            String shortName, String bestIconUrl, String bestIconMurmur2Hash, Bitmap bestIconBitmap,
-            String[] iconUrls, int displayMode, int orientation, long themeColor,
-            long backgroundColor) {
+            String shortName, String primaryIconUrl, String primaryIconMurmur2Hash,
+            Bitmap primaryIconBitmap, String[] iconUrls, int displayMode, int orientation,
+            long themeColor, long backgroundColor) {
         HashMap<String, String> iconUrlToMurmur2HashMap = new HashMap<String, String>();
         for (String iconUrl : iconUrls) {
-            String murmur2Hash = (iconUrl.equals(bestIconUrl)) ? bestIconMurmur2Hash : null;
+            String murmur2Hash = (iconUrl.equals(primaryIconUrl)) ? primaryIconMurmur2Hash : null;
             iconUrlToMurmur2HashMap.put(iconUrl, murmur2Hash);
         }
 
+        Bitmap badgeIconBitmap = null;
         WebApkInfo info = WebApkInfo.create(mOldInfo.id(), mOldInfo.uri().toString(),
-                mOldInfo.shouldForceNavigation(), scopeUrl, new WebApkInfo.Icon(bestIconBitmap),
-                name, shortName, displayMode, orientation, mOldInfo.source(), themeColor,
-                backgroundColor, mOldInfo.webApkPackageName(), mOldInfo.shellApkVersion(),
-                mOldInfo.manifestUrl(), manifestStartUrl, iconUrlToMurmur2HashMap);
-        mObserver.onGotManifestData(info, bestIconUrl);
+                mOldInfo.shouldForceNavigation(), scopeUrl, new WebApkInfo.Icon(primaryIconBitmap),
+                new WebApkInfo.Icon(badgeIconBitmap), name, shortName, displayMode, orientation,
+                mOldInfo.source(), themeColor, backgroundColor, mOldInfo.webApkPackageName(),
+                mOldInfo.shellApkVersion(), mOldInfo.manifestUrl(), manifestStartUrl,
+                iconUrlToMurmur2HashMap);
+        mObserver.onGotManifestData(info, primaryIconUrl);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappInfo.java
index 1452589..aa59629 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappInfo.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappInfo.java
@@ -283,7 +283,7 @@
     }
 
     /**
-     * Returns the icon in Bitmap form.  Caches the result for future retrievals.
+     * Returns the icon in Bitmap form.
      */
     public Bitmap icon() {
         return (mIcon == null) ? null : mIcon.decoded();
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 79c932c..32def93 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -2359,6 +2359,9 @@
       <message name="IDS_MENU_REFRESH" desc="Tooltip on Android for the button to refresh the current web page. [CHAR-LIMIT=27]">
         Refresh
       </message>
+      <message name="IDS_MENU_STOP_REFRESH" desc="Tooltip on Android for the button to stop refreshing the current web page. [CHAR-LIMIT=27]">
+        Stop refreshing
+      </message>
       <message name="IDS_MENU_NEW_TAB" desc="Menu item for opening a new tab. [CHAR-LIMIT=27]">
         New tab
       </message>
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/invalidation/InvalidationServiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/invalidation/InvalidationServiceTest.java
index 57d675ea..7a20cee 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/invalidation/InvalidationServiceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/invalidation/InvalidationServiceTest.java
@@ -50,7 +50,6 @@
         mAppContext = new IntentSavingContext(InstrumentationRegistry.getInstrumentation()
                                                       .getTargetContext()
                                                       .getApplicationContext());
-        // TODO(wnwen): Remove mAppContext and just use application context.
         // We don't want to use the system content resolver, so we override it.
         MockSyncContentResolverDelegate delegate = new MockSyncContentResolverDelegate();
         // Android master sync can safely always be on.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTest.java
index d436ba18..1fde63c6 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTest.java
@@ -23,7 +23,6 @@
 
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.DisableIf;
-import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.MinAndroidSdkLevel;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.R;
@@ -162,8 +161,7 @@
      * Tests that non-focused tabs cannot get pose information.
      */
     @Test
-    // @SmallTest
-    @DisabledTest(message = "Flaky. http://crbug.com/726986")
+    @SmallTest
     public void testPoseDataUnfocusedTab() throws InterruptedException {
         mVrTestRule.loadUrlAndAwaitInitialization(
                 VrTestRule.getHtmlTestFile("test_pose_data_unfocused_tab"), PAGE_LOAD_TIMEOUT_S);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateDataFetcherTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateDataFetcherTest.java
index 0dac493..06b7073 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateDataFetcherTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateDataFetcherTest.java
@@ -122,7 +122,7 @@
             @Override
             public void run() {
                 WebApkInfo oldInfo = WebApkInfo.create("", "", false /* forceNavigation */,
-                        scopeUrl, null, null, null, -1, -1, -1, -1, -1, "random.package", -1,
+                        scopeUrl, null, null, null, null, -1, -1, -1, -1, -1, "random.package", -1,
                         manifestUrl, "", new HashMap<String, String>());
                 fetcher.start(mTab, oldInfo, observer);
             }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerTest.java
index e10aa0f8..9c764bd8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerTest.java
@@ -163,7 +163,7 @@
             @Override
             public void run() {
                 WebApkInfo info = WebApkInfo.create(WEBAPK_ID, "", false /* forceNavigation */,
-                        creationData.scope, null, creationData.name, creationData.shortName,
+                        creationData.scope, null, null, creationData.name, creationData.shortName,
                         creationData.displayMode, creationData.orientation, 0,
                         creationData.themeColor, creationData.backgroundColor, "",
                         WebApkVersion.CURRENT_SHELL_APK_VERSION, creationData.manifestUrl,
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappVisibilityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappVisibilityTest.java
index 7fd94ef..9325278 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappVisibilityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappVisibilityTest.java
@@ -129,7 +129,7 @@
         } else {
             delegate = new WebApkBrowserControlsDelegate(null, new Tab(0, false, null));
             info = WebApkInfo.create("", "", false /* forceNavigation */, webappStartUrlOrScopeUrl,
-                    null, null, null, 0, 0, 0, 0, 0, "", 0, null, "", null);
+                    null, null, null, null, 0, 0, 0, 0, 0, "", 0, null, "", null);
         }
         return delegate.shouldShowBrowserControls(info, url, securityLevel);
     }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkInfoTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkInfoTest.java
index f1ccc06..ecaf1ae 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkInfoTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkInfoTest.java
@@ -101,6 +101,9 @@
         Assert.assertEquals(ICON_MURMUR2_HASH, info.iconUrlToMurmur2HashMap().get(ICON_URL));
 
         Assert.assertEquals(SOURCE, info.source());
+
+        Assert.assertEquals(null, info.icon());
+        Assert.assertEquals(null, info.badgeIcon());
     }
 
     /**
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerTest.java
index b619e3bf..6b36fd8 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerTest.java
@@ -184,6 +184,7 @@
         public Map<String, String> iconUrlToMurmur2HashMap;
         public String bestIconUrl;
         public Bitmap bestIcon;
+        public Bitmap badgeIcon;
         public int displayMode;
         public int orientation;
         public long themeColor;
@@ -246,6 +247,7 @@
 
         manifestData.bestIconUrl = ICON_URL;
         manifestData.bestIcon = createBitmap(Color.GREEN);
+        manifestData.badgeIcon = null;
         manifestData.displayMode = DISPLAY_MODE;
         manifestData.orientation = ORIENTATION;
         manifestData.themeColor = THEME_COLOR;
@@ -259,10 +261,10 @@
         final String kPackageName = "org.random.webapk";
         return WebApkInfo.create(getWebApkId(kPackageName), "", false /* forceNavigation */,
                 manifestData.scopeUrl, new WebApkInfo.Icon(manifestData.bestIcon),
-                manifestData.name, manifestData.shortName, manifestData.displayMode,
-                manifestData.orientation, -1, manifestData.themeColor, manifestData.backgroundColor,
-                kPackageName, -1, WEB_MANIFEST_URL, manifestData.startUrl,
-                manifestData.iconUrlToMurmur2HashMap);
+                new WebApkInfo.Icon(manifestData.badgeIcon), manifestData.name,
+                manifestData.shortName, manifestData.displayMode, manifestData.orientation, -1,
+                manifestData.themeColor, manifestData.backgroundColor, kPackageName, -1,
+                WEB_MANIFEST_URL, manifestData.startUrl, manifestData.iconUrlToMurmur2HashMap);
     }
 
     /**
diff --git a/chrome/android/webapk/libs/common/src/org/chromium/webapk/lib/common/WebApkMetaDataKeys.java b/chrome/android/webapk/libs/common/src/org/chromium/webapk/lib/common/WebApkMetaDataKeys.java
index 6b0b803..0b6f76e 100644
--- a/chrome/android/webapk/libs/common/src/org/chromium/webapk/lib/common/WebApkMetaDataKeys.java
+++ b/chrome/android/webapk/libs/common/src/org/chromium/webapk/lib/common/WebApkMetaDataKeys.java
@@ -26,4 +26,7 @@
     public static final String ICON_URLS_AND_ICON_MURMUR2_HASHES =
             "org.chromium.webapk.shell_apk.iconUrlsAndIconMurmur2Hashes";
     public static final String WEB_MANIFEST_URL = "org.chromium.webapk.shell_apk.webManifestUrl";
+    // TODO(zpeng): crbug.com/715166. Assign value to {@link BADGE_ICON_ID} and sync it with
+    // WebAPK Android Manifest.
+    public static final String BADGE_ICON_ID = "";
 }
diff --git a/chrome/app/vector_icons/BUILD.gn b/chrome/app/vector_icons/BUILD.gn
index 54db841..5b53ab1 100644
--- a/chrome/app/vector_icons/BUILD.gn
+++ b/chrome/app/vector_icons/BUILD.gn
@@ -19,6 +19,8 @@
     "autologin.icon",
     "blocked_badge.icon",
     "bluetooth_connected.icon",
+    "browser_tools_animated.1x.icon",
+    "browser_tools_animated.icon",
     "browser_tools.1x.icon",
     "browser_tools.icon",
     "browser_tools_error.icon",
diff --git a/chrome/app/vector_icons/browser_tools_animated.1x.icon b/chrome/app/vector_icons/browser_tools_animated.1x.icon
new file mode 100644
index 0000000..18abb617
--- /dev/null
+++ b/chrome/app/vector_icons/browser_tools_animated.1x.icon
@@ -0,0 +1,107 @@
+// Copyright 2017 The Chromium 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, 16,
+
+// Top dot.
+TRANSITION_FROM,
+TRANSITION_FROM,
+MOVE_TO, 7, 3.5f,
+CUBIC_TO, 7, 2.67f, 7.67f, 2, 8.5f, 2,
+R_H_LINE_TO, 0,
+CUBIC_TO, 9.33f, 2, 10, 2.67f, 10, 3.5f,
+CUBIC_TO, 10, 4.33f, 9.33f, 5, 8.5f, 5,
+R_H_LINE_TO, 0,
+CUBIC_TO, 7.67f, 5, 7, 4.33f, 7, 3.5f,
+
+TRANSITION_TO,
+MOVE_TO, 4.68f, 3.5f,
+CUBIC_TO, 4.68f, 2.95f, 5.13f, 2.5f, 5.68f, 2.5f,
+R_H_LINE_TO, 5.65f,
+CUBIC_TO, 11.87f, 2.5f, 12.32f, 2.95f, 12.32f, 3.5f,
+CUBIC_TO, 12.32f, 4.05f, 11.87f, 4.5f, 11.32f, 4.5f,
+R_H_LINE_TO, -5.65f,
+CUBIC_TO, 5.13f, 4.5f, 4.68f, 4.05f, 4.68f, 2.5f,
+TRANSITION_END, 133, 150, gfx::Tween::FAST_OUT_SLOW_IN,
+
+TRANSITION_TO,
+MOVE_TO, 7, 3.5f,
+CUBIC_TO, 7, 2.67f, 7.67f, 2, 8.5f, 2,
+LINE_TO, 8.5f, 2,
+CUBIC_TO, 9.33f, 2, 10, 2.67f, 10, 3.5f,
+CUBIC_TO, 10, 4.33f, 9.33f, 5, 8.5f, 5,
+LINE_TO, 8.5f, 5,
+CUBIC_TO, 7.67f, 5, 7, 4.33f, 7, 3.5f,
+TRANSITION_END, 416, 533, gfx::Tween::FAST_OUT_SLOW_IN,
+
+CLOSE,
+NEW_PATH,
+
+// Middle dot.
+TRANSITION_FROM,
+TRANSITION_FROM,
+MOVE_TO, 7, 8.5f,
+CUBIC_TO, 7, 7.67f, 7.67f, 7, 8.5f, 7,
+R_H_LINE_TO, 0,
+CUBIC_TO, 9.33f, 7, 10, 7.67f, 10, 8.5f,
+CUBIC_TO, 10, 9.33f, 9.33f, 10, 8.5f, 10,
+R_H_LINE_TO, 0,
+CUBIC_TO, 7.67f, 10, 7, 9.33f, 7, 8.5f,
+
+TRANSITION_TO,
+MOVE_TO, 4.68f, 8.5f,
+CUBIC_TO, 4.68f, 7.95f, 5.13f, 7.5f, 5.68f, 7.5f,
+R_H_LINE_TO, 5.65f,
+CUBIC_TO, 11.87f, 7.5f, 12.32f, 7.95f, 12.32f, 8.5f,
+CUBIC_TO, 12.32f, 9.05f, 11.87f, 9.5f, 11.32f, 9.5f,
+R_H_LINE_TO, -5.65f,
+CUBIC_TO, 5.13f, 9.5f, 4.68f, 9.05f, 4.68f, 7.5f,
+TRANSITION_END, 67, 150, gfx::Tween::FAST_OUT_SLOW_IN,
+
+TRANSITION_TO,
+MOVE_TO, 7, 8.5f,
+CUBIC_TO, 7, 7.67f, 7.67f, 7, 8.5f, 7,
+R_H_LINE_TO, 0,
+CUBIC_TO, 9.33f, 7, 10, 7.67f, 10, 8.5f,
+CUBIC_TO, 10, 9.33f, 9.33f, 10, 8.5f, 10,
+R_H_LINE_TO, 0,
+CUBIC_TO, 7.67f, 10, 7, 9.33f, 7, 8.5f,
+TRANSITION_END, 350, 383, gfx::Tween::FAST_OUT_SLOW_IN,
+
+CLOSE,
+NEW_PATH,
+
+// Bottom dot.
+TRANSITION_FROM,
+TRANSITION_FROM,
+MOVE_TO, 7, 13.5f,
+CUBIC_TO, 7, 12.67f, 7.67f, 12, 8.5f, 12,
+R_H_LINE_TO, 0,
+CUBIC_TO, 9.33f, 12, 10, 12.67f, 10, 13.5f,
+CUBIC_TO, 10, 14.33f, 9.33f, 15, 8.5f, 15,
+R_H_LINE_TO, 0,
+CUBIC_TO, 7.67f, 15, 7, 14.33f, 7, 13.5f,
+
+TRANSITION_TO,
+MOVE_TO, 4.68f, 13.5f,
+CUBIC_TO, 4.68f, 12.95f, 5.13f, 12.5f, 5.68f, 12.5f,
+R_H_LINE_TO, 5.65f,
+CUBIC_TO, 11.87f, 12.5f, 12.32f, 12.95f, 12.32f, 13.5f,
+CUBIC_TO, 12.32f, 14.05f, 11.87f, 14.5f, 11.32f, 14.5f,
+R_H_LINE_TO, -5.65f,
+CUBIC_TO, 5.13f, 14.5f, 4.68f, 14.05f, 4.68f, 12.5f,
+TRANSITION_END, 0, 150, gfx::Tween::FAST_OUT_SLOW_IN,
+
+TRANSITION_TO,
+MOVE_TO, 7, 13.5f,
+CUBIC_TO, 7, 12.67f, 7.67f, 12, 8.5f, 12,
+R_H_LINE_TO, 0,
+CUBIC_TO, 9.33f, 12, 10, 12.67f, 10, 13.5f,
+CUBIC_TO, 10, 14.33f, 9.33f, 15, 8.5f, 15,
+R_H_LINE_TO, 0,
+CUBIC_TO, 7.67f, 15, 7, 14.33f, 7, 13.5f,
+TRANSITION_END, 283, 400,  gfx::Tween::FAST_OUT_SLOW_IN,
+
+CLOSE,
+END
diff --git a/chrome/app/vector_icons/browser_tools_animated.icon b/chrome/app/vector_icons/browser_tools_animated.icon
new file mode 100644
index 0000000..c1e7dc7
--- /dev/null
+++ b/chrome/app/vector_icons/browser_tools_animated.icon
@@ -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.
+
+// TODO(estade): this is copied from 1x. Instead, apply motion to the unanimated
+// 2x asset.
+
+CANVAS_DIMENSIONS, 16,
+
+// Top dot.
+TRANSITION_FROM,
+TRANSITION_FROM,
+MOVE_TO, 7, 3.5f,
+CUBIC_TO, 7, 2.67f, 7.67f, 2, 8.5f, 2,
+R_H_LINE_TO, 0,
+CUBIC_TO, 9.33f, 2, 10, 2.67f, 10, 3.5f,
+CUBIC_TO, 10, 4.33f, 9.33f, 5, 8.5f, 5,
+R_H_LINE_TO, 0,
+CUBIC_TO, 7.67f, 5, 7, 4.33f, 7, 3.5f,
+
+TRANSITION_TO,
+MOVE_TO, 4.68f, 3.5f,
+CUBIC_TO, 4.68f, 2.95f, 5.13f, 2.5f, 5.68f, 2.5f,
+R_H_LINE_TO, 5.65f,
+CUBIC_TO, 11.87f, 2.5f, 12.32f, 2.95f, 12.32f, 3.5f,
+CUBIC_TO, 12.32f, 4.05f, 11.87f, 4.5f, 11.32f, 4.5f,
+R_H_LINE_TO, -5.65f,
+CUBIC_TO, 5.13f, 4.5f, 4.68f, 4.05f, 4.68f, 2.5f,
+TRANSITION_END, 133, 150, gfx::Tween::FAST_OUT_SLOW_IN,
+
+TRANSITION_TO,
+MOVE_TO, 7, 3.5f,
+CUBIC_TO, 7, 2.67f, 7.67f, 2, 8.5f, 2,
+LINE_TO, 8.5f, 2,
+CUBIC_TO, 9.33f, 2, 10, 2.67f, 10, 3.5f,
+CUBIC_TO, 10, 4.33f, 9.33f, 5, 8.5f, 5,
+LINE_TO, 8.5f, 5,
+CUBIC_TO, 7.67f, 5, 7, 4.33f, 7, 3.5f,
+TRANSITION_END, 416, 533, gfx::Tween::FAST_OUT_SLOW_IN,
+
+CLOSE,
+NEW_PATH,
+
+// Middle dot.
+TRANSITION_FROM,
+TRANSITION_FROM,
+MOVE_TO, 7, 8.5f,
+CUBIC_TO, 7, 7.67f, 7.67f, 7, 8.5f, 7,
+R_H_LINE_TO, 0,
+CUBIC_TO, 9.33f, 7, 10, 7.67f, 10, 8.5f,
+CUBIC_TO, 10, 9.33f, 9.33f, 10, 8.5f, 10,
+R_H_LINE_TO, 0,
+CUBIC_TO, 7.67f, 10, 7, 9.33f, 7, 8.5f,
+
+TRANSITION_TO,
+MOVE_TO, 4.68f, 8.5f,
+CUBIC_TO, 4.68f, 7.95f, 5.13f, 7.5f, 5.68f, 7.5f,
+R_H_LINE_TO, 5.65f,
+CUBIC_TO, 11.87f, 7.5f, 12.32f, 7.95f, 12.32f, 8.5f,
+CUBIC_TO, 12.32f, 9.05f, 11.87f, 9.5f, 11.32f, 9.5f,
+R_H_LINE_TO, -5.65f,
+CUBIC_TO, 5.13f, 9.5f, 4.68f, 9.05f, 4.68f, 7.5f,
+TRANSITION_END, 67, 150, gfx::Tween::FAST_OUT_SLOW_IN,
+
+TRANSITION_TO,
+MOVE_TO, 7, 8.5f,
+CUBIC_TO, 7, 7.67f, 7.67f, 7, 8.5f, 7,
+R_H_LINE_TO, 0,
+CUBIC_TO, 9.33f, 7, 10, 7.67f, 10, 8.5f,
+CUBIC_TO, 10, 9.33f, 9.33f, 10, 8.5f, 10,
+R_H_LINE_TO, 0,
+CUBIC_TO, 7.67f, 10, 7, 9.33f, 7, 8.5f,
+TRANSITION_END, 350, 383, gfx::Tween::FAST_OUT_SLOW_IN,
+
+CLOSE,
+NEW_PATH,
+
+// Bottom dot.
+TRANSITION_FROM,
+TRANSITION_FROM,
+MOVE_TO, 7, 13.5f,
+CUBIC_TO, 7, 12.67f, 7.67f, 12, 8.5f, 12,
+R_H_LINE_TO, 0,
+CUBIC_TO, 9.33f, 12, 10, 12.67f, 10, 13.5f,
+CUBIC_TO, 10, 14.33f, 9.33f, 15, 8.5f, 15,
+R_H_LINE_TO, 0,
+CUBIC_TO, 7.67f, 15, 7, 14.33f, 7, 13.5f,
+
+TRANSITION_TO,
+MOVE_TO, 4.68f, 13.5f,
+CUBIC_TO, 4.68f, 12.95f, 5.13f, 12.5f, 5.68f, 12.5f,
+R_H_LINE_TO, 5.65f,
+CUBIC_TO, 11.87f, 12.5f, 12.32f, 12.95f, 12.32f, 13.5f,
+CUBIC_TO, 12.32f, 14.05f, 11.87f, 14.5f, 11.32f, 14.5f,
+R_H_LINE_TO, -5.65f,
+CUBIC_TO, 5.13f, 14.5f, 4.68f, 14.05f, 4.68f, 12.5f,
+TRANSITION_END, 0, 150, gfx::Tween::FAST_OUT_SLOW_IN,
+
+TRANSITION_TO,
+MOVE_TO, 7, 13.5f,
+CUBIC_TO, 7, 12.67f, 7.67f, 12, 8.5f, 12,
+R_H_LINE_TO, 0,
+CUBIC_TO, 9.33f, 12, 10, 12.67f, 10, 13.5f,
+CUBIC_TO, 10, 14.33f, 9.33f, 15, 8.5f, 15,
+R_H_LINE_TO, 0,
+CUBIC_TO, 7.67f, 15, 7, 14.33f, 7, 13.5f,
+TRANSITION_END, 283, 400,  gfx::Tween::FAST_OUT_SLOW_IN,
+
+CLOSE,
+END
diff --git a/chrome/app/vector_icons/vector_icons.cc.template b/chrome/app/vector_icons/vector_icons.cc.template
index 577bf85..99cc4a75 100644
--- a/chrome/app/vector_icons/vector_icons.cc.template
+++ b/chrome/app/vector_icons/vector_icons.cc.template
@@ -8,6 +8,7 @@
 #include "chrome/app/vector_icons/vector_icons.h"
 
 #include "base/logging.h"
+#include "ui/gfx/animation/tween.h"
 #include "ui/gfx/vector_icon_types.h"
 
 #define PATH_ELEMENT_TEMPLATE(path_name, ...) \
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 542d001..d3d4dfa 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1173,6 +1173,8 @@
     "safe_browsing/chrome_cleaner/srt_field_trial_win.h",
     "safe_browsing/chrome_cleaner/srt_global_error_win.cc",
     "safe_browsing/chrome_cleaner/srt_global_error_win.h",
+    "safe_browsing/mojo_safe_browsing_impl.cc",
+    "safe_browsing/mojo_safe_browsing_impl.h",
     "safe_browsing/safe_browsing_tab_observer.cc",
     "safe_browsing/safe_browsing_tab_observer.h",
     "safe_search_api/safe_search_url_checker.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 765442e2..26f3eb9 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2822,6 +2822,9 @@
      flag_descriptions::kOmniboxEntitySuggestionsName,
      flag_descriptions::kOmniboxEntitySuggestionsDescription, kOsDesktop,
      FEATURE_VALUE_TYPE(omnibox::kOmniboxEntitySuggestions)},
+    {"omnibox-tail-suggestions", flag_descriptions::kOmniboxTailSuggestionsName,
+     flag_descriptions::kOmniboxTailSuggestionsDescription, kOsDesktop,
+     FEATURE_VALUE_TYPE(omnibox::kOmniboxTailSuggestions)},
     {"enable-new-app-menu-icon", flag_descriptions::kEnableNewAppMenuIconName,
      flag_descriptions::kEnableNewAppMenuIconDescription, kOsDesktop,
      SINGLE_VALUE_TYPE(switches::kEnableNewAppMenuIcon)},
diff --git a/chrome/browser/autofill/content_autofill_driver_browsertest.cc b/chrome/browser/autofill/content_autofill_driver_browsertest.cc
index de7a4db..117c6ae3 100644
--- a/chrome/browser/autofill/content_autofill_driver_browsertest.cc
+++ b/chrome/browser/autofill/content_autofill_driver_browsertest.cc
@@ -60,11 +60,11 @@
  public:
   TestContentAutofillDriver(content::RenderFrameHost* rfh,
                             AutofillClient* client)
-      : ContentAutofillDriver(
-            rfh,
-            client,
-            g_browser_process->GetApplicationLocale(),
-            AutofillManager::ENABLE_AUTOFILL_DOWNLOAD_MANAGER) {}
+      : ContentAutofillDriver(rfh,
+                              client,
+                              g_browser_process->GetApplicationLocale(),
+                              AutofillManager::ENABLE_AUTOFILL_DOWNLOAD_MANAGER,
+                              nullptr) {}
   ~TestContentAutofillDriver() override {}
 
  private:
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 37e6a5d..12d496f 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -74,6 +74,8 @@
 #include "chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h"
 #include "chrome/browser/safe_browsing/certificate_reporting_service.h"
 #include "chrome/browser/safe_browsing/certificate_reporting_service_factory.h"
+#include "chrome/browser/safe_browsing/mojo_safe_browsing_impl.h"
+#include "chrome/browser/safe_browsing/safe_browsing_service.h"
 #include "chrome/browser/search/instant_service.h"
 #include "chrome/browser/search/instant_service_factory.h"
 #include "chrome/browser/search/search.h"
@@ -3089,6 +3091,18 @@
     registry->AddInterface(
         base::Bind(&NetBenchmarking::Create, profile, context));
   }
+
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableNetworkService)) {
+    registry->AddInterface(
+        base::Bind(
+            &safe_browsing::MojoSafeBrowsingImpl::Create,
+            g_browser_process->safe_browsing_service()->database_manager(),
+            g_browser_process->safe_browsing_service()->ui_manager(),
+            render_process_host->GetID()),
+        BrowserThread::GetTaskRunnerForThread(BrowserThread::IO));
+  }
+
 #if defined(OS_WIN)
   if (base::FeatureList::IsEnabled(features::kModuleDatabase)) {
     // Add the ModuleDatabase interface. This is the interface used by renderer
diff --git a/chrome/browser/chrome_content_browser_manifest_overlay.json b/chrome/browser/chrome_content_browser_manifest_overlay.json
index 0f1241c..347ba25 100644
--- a/chrome/browser/chrome_content_browser_manifest_overlay.json
+++ b/chrome/browser/chrome_content_browser_manifest_overlay.json
@@ -9,6 +9,7 @@
           "autofill::mojom::PasswordManagerDriver",
           "chrome::mojom::CacheStatsRecorder",
           "chrome::mojom::NetBenchmarking",
+          "chrome::mojom::SafeBrowsing",
           "extensions::StashService",
           "metrics::mojom::LeakDetector",
           "mojom::ModuleEventSink",
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 483145cd..0074d39 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -714,6 +714,8 @@
     "lock_screen_apps/state_controller.cc",
     "lock_screen_apps/state_controller.h",
     "lock_screen_apps/state_observer.h",
+    "logging.cc",
+    "logging.h",
     "login/app_launch_controller.cc",
     "login/app_launch_controller.h",
     "login/app_launch_signin_screen.cc",
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index 15af8d2..d83e655 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -56,6 +56,7 @@
 #include "chrome/browser/chromeos/input_method/input_method_configuration.h"
 #include "chrome/browser/chromeos/language_preferences.h"
 #include "chrome/browser/chromeos/lock_screen_apps/state_controller.h"
+#include "chrome/browser/chromeos/logging.h"
 #include "chrome/browser/chromeos/login/helper.h"
 #include "chrome/browser/chromeos/login/lock/screen_locker.h"
 #include "chrome/browser/chromeos/login/login_wizard.h"
diff --git a/chrome/browser/chromeos/logging.cc b/chrome/browser/chromeos/logging.cc
new file mode 100644
index 0000000..41a1302
--- /dev/null
+++ b/chrome/browser/chromeos/logging.cc
@@ -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.
+
+#include "chrome/browser/chromeos/logging.h"
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/task_scheduler/post_task.h"
+#include "chrome/common/logging_chrome.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace logging {
+
+namespace {
+
+// This should be true for exactly the period between the end of
+// InitChromeLogging() and the beginning of CleanupChromeLogging().
+bool chrome_logging_redirected_ = false;
+
+void SymlinkSetUp(const base::CommandLine& command_line,
+                  const base::FilePath& log_path,
+                  const base::FilePath& target_path) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  // ChromeOS always logs through the symlink, so it shouldn't be
+  // deleted if it already exists.
+  logging::LoggingSettings settings;
+  settings.logging_dest = DetermineLoggingDestination(command_line);
+  settings.log_file = log_path.value().c_str();
+  if (!logging::InitLogging(settings)) {
+    DLOG(ERROR) << "Unable to initialize logging to " << log_path.value();
+    base::PostTaskWithTraits(
+        FROM_HERE, {base::MayBlock()},
+        base::Bind(&RemoveSymlinkAndLog, log_path, target_path));
+  } else {
+    chrome_logging_redirected_ = true;
+  }
+}
+
+}  // namespace
+
+void RedirectChromeLogging(const base::CommandLine& command_line) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  if (chrome_logging_redirected_) {
+    // TODO: Support multiple active users. http://crbug.com/230345
+    LOG(WARNING) << "NOT redirecting logging for multi-profiles case.";
+    return;
+  }
+
+  DCHECK(!chrome_logging_redirected_)
+      << "Attempted to redirect logging when it was already initialized.";
+
+  // Redirect logs to the session log directory, if set.  Otherwise
+  // defaults to the profile dir.
+  const base::FilePath log_path = GetSessionLogFile(command_line);
+
+  // Always force a new symlink when redirecting.
+  base::PostTaskWithTraitsAndReplyWithResult(
+      FROM_HERE, {base::MayBlock()},
+      base::BindOnce(&SetUpSymlinkIfNeeded, log_path, true),
+      base::BindOnce(&SymlinkSetUp, command_line, log_path));
+}
+
+}  // namespace logging
diff --git a/chrome/browser/chromeos/logging.h b/chrome/browser/chromeos/logging.h
new file mode 100644
index 0000000..05be4d09
--- /dev/null
+++ b/chrome/browser/chromeos/logging.h
@@ -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.
+
+#ifndef CHROME_BROWSER_CHROMEOS_LOGGING_H_
+#define CHROME_BROWSER_CHROMEOS_LOGGING_H_
+
+namespace base {
+class CommandLine;
+}
+
+namespace logging {
+
+// Redirects chrome logging to the appropriate session log dir.
+void RedirectChromeLogging(const base::CommandLine& command_line);
+
+}  // namespace logging
+
+#endif  // CHROME_BROWSER_CHROMEOS_LOGGING_H_
diff --git a/chrome/browser/chromeos/login/chrome_restart_request.cc b/chrome/browser/chromeos/login/chrome_restart_request.cc
index dc2a45b6..348bdb7 100644
--- a/chrome/browser/chromeos/login/chrome_restart_request.cc
+++ b/chrome/browser/chromeos/login/chrome_restart_request.cc
@@ -85,7 +85,6 @@
     ::switches::kDisableCastStreamingHWEncoding,
     ::switches::kDisableDistanceFieldText,
     ::switches::kDisableGpu,
-    ::switches::kDisableGpuAsyncWorkerContext,
     ::switches::kDisableGpuMemoryBufferVideoFrames,
     ::switches::kDisableGpuShaderDiskCache,
     ::switches::kUsePassthroughCmdDecoder,
@@ -110,7 +109,6 @@
     ::switches::kForceDisplayList2dCanvas,
     ::switches::kDisableGpuSandbox,
     ::switches::kEnableDistanceFieldText,
-    ::switches::kEnableGpuAsyncWorkerContext,
     ::switches::kEnableGpuMemoryBufferVideoFrames,
     ::switches::kEnableGpuRasterization,
     ::switches::kEnableLogging,
diff --git a/chrome/browser/chromeos/login/session/user_session_manager.cc b/chrome/browser/chromeos/login/session/user_session_manager.cc
index b4d6e51..aa390e08 100644
--- a/chrome/browser/chromeos/login/session/user_session_manager.cc
+++ b/chrome/browser/chromeos/login/session/user_session_manager.cc
@@ -37,6 +37,7 @@
 #include "chrome/browser/chromeos/boot_times_recorder.h"
 #include "chrome/browser/chromeos/first_run/first_run.h"
 #include "chrome/browser/chromeos/first_run/goodies_displayer.h"
+#include "chrome/browser/chromeos/logging.h"
 #include "chrome/browser/chromeos/login/auth/chrome_cryptohome_authenticator.h"
 #include "chrome/browser/chromeos/login/chrome_restart_request.h"
 #include "chrome/browser/chromeos/login/demo_mode/demo_app_launcher.h"
@@ -980,7 +981,7 @@
 void UserSessionManager::PreStartSession() {
   // Switch log file as soon as possible.
   if (base::SysInfo::IsRunningOnChromeOS())
-    logging::RedirectChromeLogging(*(base::CommandLine::ForCurrentProcess()));
+    logging::RedirectChromeLogging(*base::CommandLine::ForCurrentProcess());
 }
 
 void UserSessionManager::StoreUserContextDataBeforeProfileIsCreated() {
diff --git a/chrome/browser/cryptauth/chrome_cryptauth_service.cc b/chrome/browser/cryptauth/chrome_cryptauth_service.cc
index cb91f83..cd4673c 100644
--- a/chrome/browser/cryptauth/chrome_cryptauth_service.cc
+++ b/chrome/browser/cryptauth/chrome_cryptauth_service.cc
@@ -21,7 +21,6 @@
 #include "components/cryptauth/cryptauth_device_manager.h"
 #include "components/cryptauth/cryptauth_enroller.h"
 #include "components/cryptauth/cryptauth_enroller_impl.h"
-#include "components/cryptauth/cryptauth_enrollment_manager.h"
 #include "components/cryptauth/cryptauth_enrollment_utils.h"
 #include "components/cryptauth/cryptauth_gcm_manager_impl.h"
 #include "components/cryptauth/proto/cryptauth_api.pb.h"
@@ -226,8 +225,7 @@
                  << "waiting before starting CryptAuth managers.";
     token_service_->AddObserver(this);
   } else {
-    enrollment_manager_->Start();
-    device_manager_->Start();
+    PerformEnrollmentAndDeviceSync();
   }
 }
 
@@ -268,11 +266,36 @@
   return CreateCryptAuthClientFactoryImpl(profile_);
 }
 
+void ChromeCryptAuthService::OnEnrollmentStarted() {}
+
+void ChromeCryptAuthService::OnEnrollmentFinished(bool success) {
+  if (success)
+    device_manager_->Start();
+  else
+    PA_LOG(ERROR) << "CryptAuth enrollment failed. Device manager was not "
+                  << " started.";
+
+  enrollment_manager_->RemoveObserver(this);
+}
+
 void ChromeCryptAuthService::OnRefreshTokenAvailable(
     const std::string& account_id) {
   if (account_id == GetAccountId()) {
     token_service_->RemoveObserver(this);
-    enrollment_manager_->Start();
-    device_manager_->Start();
+    PerformEnrollmentAndDeviceSync();
   }
 }
+
+void ChromeCryptAuthService::PerformEnrollmentAndDeviceSync() {
+  if (enrollment_manager_->IsEnrollmentValid()) {
+    device_manager_->Start();
+  } else {
+    // If enrollment is not valid, wait for the new enrollment attempt to finish
+    // before starting CryptAuthDeviceManager. See OnEnrollmentFinished(),
+    enrollment_manager_->AddObserver(this);
+  }
+
+  // Even if enrollment was valid, CryptAuthEnrollmentManager must be started in
+  // order to schedule the next enrollment attempt.
+  enrollment_manager_->Start();
+}
diff --git a/chrome/browser/cryptauth/chrome_cryptauth_service.h b/chrome/browser/cryptauth/chrome_cryptauth_service.h
index 21f8f700..9aa6c11e 100644
--- a/chrome/browser/cryptauth/chrome_cryptauth_service.h
+++ b/chrome/browser/cryptauth/chrome_cryptauth_service.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "components/cryptauth/cryptauth_enrollment_manager.h"
 #include "components/cryptauth/cryptauth_service.h"
 #include "components/cryptauth/proto/cryptauth_api.pb.h"
 #include "components/keyed_service/core/keyed_service.h"
@@ -20,9 +21,11 @@
 }  // namespace cryptauth
 
 // Implementation of cryptauth::CryptAuthService.
-class ChromeCryptAuthService : public KeyedService,
-                               public cryptauth::CryptAuthService,
-                               public OAuth2TokenService::Observer {
+class ChromeCryptAuthService
+    : public KeyedService,
+      public cryptauth::CryptAuthService,
+      public cryptauth::CryptAuthEnrollmentManager::Observer,
+      public OAuth2TokenService::Observer {
  public:
   static std::unique_ptr<ChromeCryptAuthService> Create(Profile* profile);
   ~ChromeCryptAuthService() override;
@@ -41,6 +44,10 @@
   std::unique_ptr<cryptauth::CryptAuthClientFactory>
   CreateCryptAuthClientFactory() override;
 
+  // cryptauth::CryptAuthEnrollmentManager::Observer:
+  void OnEnrollmentStarted() override;
+  void OnEnrollmentFinished(bool success) override;
+
  protected:
   // Note: ChromeCryptAuthServiceFactory DependsOn(OAuth2TokenServiceFactory),
   // so |token_service| is guaranteed to outlast this service.
@@ -55,6 +62,8 @@
   // OAuth2TokenService::Observer:
   void OnRefreshTokenAvailable(const std::string& account_id) override;
 
+  void PerformEnrollmentAndDeviceSync();
+
   std::unique_ptr<cryptauth::CryptAuthGCMManager> gcm_manager_;
   std::unique_ptr<cryptauth::CryptAuthEnrollmentManager> enrollment_manager_;
   std::unique_ptr<cryptauth::CryptAuthDeviceManager> device_manager_;
diff --git a/chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc b/chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc
index 2cf800a..19be8e0 100644
--- a/chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc
+++ b/chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc
@@ -195,30 +195,36 @@
   for (auto& observer : observers_)
     observer.OnPageResourceLoad(*request, &entry->data_use());
 
-  bool will_datause_complete = false;
+  const auto frame_iter =
+      main_render_frame_data_use_map_.find(entry->main_frame_id());
+
+  // Check whether the frame is tracked in the main render frame map, and if it
+  // is, check if |entry| is currently tracked by that frame.
+  bool frame_is_tracked = frame_iter != main_render_frame_data_use_map_.end() &&
+                          frame_iter->second == entry;
+
+  // For non-main frame requests, the page load can only be tracked in the frame
+  // map.
+  bool page_load_is_tracked = frame_is_tracked;
+
   const content::ResourceRequestInfo* request_info =
       content::ResourceRequestInfo::ForRequest(request);
 
-  if (request_info &&
+  // If the frame is not tracked, but this is a main frame request, it might be
+  // the case that the navigation has not commit yet.
+  if (!frame_is_tracked && request_info &&
       request_info->GetResourceType() == content::RESOURCE_TYPE_MAIN_FRAME) {
-    will_datause_complete =
-        pending_navigation_data_use_map_.find(entry->main_frame_request_id()) ==
+    page_load_is_tracked =
+        pending_navigation_data_use_map_.find(entry->main_frame_request_id()) !=
         pending_navigation_data_use_map_.end();
-  } else {
-    // Non-mainframe, Services, and other requests.
-    const auto frame_iter =
-        main_render_frame_data_use_map_.find(entry->main_frame_id());
-    will_datause_complete =
-        frame_iter == main_render_frame_data_use_map_.end() ||
-        !frame_iter->second->HasPendingURLRequest(request);
   }
 
   DataUseAscriber::OnUrlRequestDestroyed(request);
-  request->RemoveUserData(DataUseRecorderEntryAsUserData::kUserDataKey);
 
-  if (entry->IsDataUseComplete() && will_datause_complete) {
+  // If all requests are done for |entry| and no more requests can be attributed
+  // to it, it is safe to delete.
+  if (entry->IsDataUseComplete() && !page_load_is_tracked) {
     NotifyDataUseCompleted(entry);
-    main_render_frame_data_use_map_.erase(entry->main_frame_id());
     data_use_recorders_.erase(entry);
   }
 }
diff --git a/chrome/browser/data_use_measurement/chrome_data_use_ascriber_unittest.cc b/chrome/browser/data_use_measurement/chrome_data_use_ascriber_unittest.cc
index a2bf680..7f0ef84 100644
--- a/chrome/browser/data_use_measurement/chrome_data_use_ascriber_unittest.cc
+++ b/chrome/browser/data_use_measurement/chrome_data_use_ascriber_unittest.cc
@@ -75,8 +75,10 @@
         GURL(url), net::IDLE, nullptr, TRAFFIC_ANNOTATION_FOR_TESTS);
     // TODO(kundaji): Allow request_id to be specified in AllocateForTesting.
     content::ResourceRequestInfo::AllocateForTesting(
-        request.get(), content::RESOURCE_TYPE_MAIN_FRAME, resource_context(),
-        render_process_id,
+        request.get(),
+        is_main_frame ? content::RESOURCE_TYPE_MAIN_FRAME
+                      : content::RESOURCE_TYPE_SCRIPT,
+        resource_context(), render_process_id,
         /*render_view_id=*/-1, render_frame_id, is_main_frame,
         /*parent_is_main_frame=*/false,
         /*allow_download=*/false,
@@ -227,6 +229,76 @@
   EXPECT_EQ(0u, recorders().size());
 }
 
+TEST_F(ChromeDataUseAscriberTest, SubResourceRequestsAttributed) {
+  // A regression test that verifies that subframe requests in the second page
+  // load in the same frame get attributed to the entry correctly.
+  std::unique_ptr<net::URLRequest> page_load_a_main_frame_request =
+      CreateNewRequest("http://test.com", true, kRequestId, kRenderProcessId,
+                       kRenderFrameId);
+
+  ascriber()->RenderFrameCreated(kRenderProcessId, kRenderFrameId, -1, -1);
+
+  // Start the main frame reuqest.
+  ascriber()->OnBeforeUrlRequest(page_load_a_main_frame_request.get());
+
+  // Commit the page load.
+  ascriber()->DidStartMainFrameNavigation(GURL("http://test.com"),
+                                          kRenderProcessId, kRenderFrameId,
+                                          kNavigationHandle);
+  ascriber()->ReadyToCommitMainFrameNavigation(
+      content::GlobalRequestID(kRenderProcessId, 0), kRenderProcessId,
+      kRenderFrameId);
+  ascriber()->DidFinishNavigation(kRenderProcessId, kRenderFrameId,
+                                  GURL("http://mobile.test.com"), false,
+                                  kPageTransition);
+
+  std::unique_ptr<net::URLRequest> page_load_b_main_frame_request =
+      CreateNewRequest("http://test_2.com", true, kRequestId + 1,
+                       kRenderProcessId, kRenderFrameId);
+  std::unique_ptr<net::URLRequest> page_load_b_sub_request =
+      CreateNewRequest("http://test_2.com/s", false, kRequestId + 2,
+                       kRenderProcessId, kRenderFrameId);
+
+  // Start the second main frame request.
+  ascriber()->OnBeforeUrlRequest(page_load_b_main_frame_request.get());
+
+  // Commit the second page load.
+  ascriber()->DidStartMainFrameNavigation(GURL("http://test_2.com"),
+                                          kRenderProcessId, kRenderFrameId,
+                                          kNavigationHandle);
+  ascriber()->ReadyToCommitMainFrameNavigation(
+      content::GlobalRequestID(kRenderProcessId, 0), kRenderProcessId,
+      kRenderFrameId);
+  ascriber()->DidFinishNavigation(kRenderProcessId, kRenderFrameId,
+                                  GURL("http://mobile.test_2.com"), false,
+                                  kPageTransition);
+
+  // Delete the first main frame request.
+  ascriber()->OnUrlRequestDestroyed(page_load_a_main_frame_request.get());
+
+  // Start the sub resource request for the second page load.
+  ascriber()->OnBeforeUrlRequest(page_load_b_sub_request.get());
+  ascriber()->OnNetworkBytesReceived(page_load_b_sub_request.get(), 100);
+
+  EXPECT_EQ(1u, recorders().size());
+  auto& recorder_entry = recorders().front();
+  EXPECT_EQ(RenderFrameHostID(kRenderProcessId, kRenderFrameId),
+            recorder_entry.main_frame_id());
+  EXPECT_EQ(content::GlobalRequestID(kRenderProcessId, 0),
+            recorder_entry.main_frame_request_id());
+  EXPECT_EQ(GURL("http://mobile.test_2.com"), recorder_entry.data_use().url());
+  EXPECT_EQ(DataUse::TrafficType::USER_TRAFFIC,
+            recorder_entry.data_use().traffic_type());
+  // Verify that the data usage for the sub-resource was counted towards the
+  // entry.
+  EXPECT_EQ(100, recorder_entry.data_use().total_bytes_received());
+
+  ascriber()->OnUrlRequestDestroyed(page_load_b_sub_request.get());
+  ascriber()->OnUrlRequestDestroyed(page_load_b_main_frame_request.get());
+  ascriber()->RenderFrameDeleted(kRenderProcessId, kRenderFrameId, -1, -1);
+  EXPECT_EQ(0u, recorders().size());
+}
+
 TEST_F(ChromeDataUseAscriberTest, FailedMainFrameNavigation) {
   std::unique_ptr<net::URLRequest> request = CreateNewRequest(
       "http://test.com", true, kRequestId, kRenderProcessId, kRenderFrameId);
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 7fe282edf..ee3cb30 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -2849,9 +2849,14 @@
     defined(OS_WIN)
 
 const char kOmniboxEntitySuggestionsName[] = "Omnibox entity suggestions";
-
 const char kOmniboxEntitySuggestionsDescription[] =
-    "Enable receiving entity suggestions in Omnibox.";
+    "Enable receiving entity suggestions - disambiguation descriptions - for "
+    "Omnibox suggestions.";
+
+const char kOmniboxTailSuggestionsName[] = "Omnibox tail suggestions";
+const char kOmniboxTailSuggestionsDescription[] =
+    "Enable receiving tail suggestions, a type of search suggestion "
+    "based on the last few words in the query, for the Omnibox.";
 
 const char kPauseBackgroundTabsName[] = "Pause background tabs";
 const char kPauseBackgroundTabsDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index f30e45f..1c2adae 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1388,6 +1388,9 @@
 extern const char kOmniboxEntitySuggestionsName[];
 extern const char kOmniboxEntitySuggestionsDescription[];
 
+extern const char kOmniboxTailSuggestionsName[];
+extern const char kOmniboxTailSuggestionsDescription[];
+
 extern const char kOneGoogleBarOnLocalNtpName[];
 extern const char kOneGoogleBarOnLocalNtpDescription[];
 
diff --git a/chrome/browser/printing/background_printing_manager.cc b/chrome/browser/printing/background_printing_manager.cc
index 6912ec1..330ecb9 100644
--- a/chrome/browser/printing/background_printing_manager.cc
+++ b/chrome/browser/printing/background_printing_manager.cc
@@ -56,7 +56,7 @@
 }
 
 BackgroundPrintingManager::~BackgroundPrintingManager() {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // The might be some WebContentses still in |printing_contents_map_| at this
   // point (e.g. when the last remaining tab closes and there is still a print
   // preview WebContents trying to print). In such a case it will fail to print,
@@ -66,7 +66,7 @@
 
 void BackgroundPrintingManager::OwnPrintPreviewDialog(
     WebContents* preview_dialog) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(PrintPreviewDialogController::IsPrintPreviewDialog(preview_dialog));
   CHECK(!HasPrintPreviewDialog(preview_dialog));
 
diff --git a/chrome/browser/printing/background_printing_manager.h b/chrome/browser/printing/background_printing_manager.h
index 6957e541..ff0bd1e 100644
--- a/chrome/browser/printing/background_printing_manager.h
+++ b/chrome/browser/printing/background_printing_manager.h
@@ -11,7 +11,7 @@
 
 #include "base/compiler_specific.h"
 #include "base/macros.h"
-#include "base/threading/non_thread_safe.h"
+#include "base/sequence_checker.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 
@@ -26,8 +26,7 @@
 // The hidden WebContents are no longer part of any Browser / TabStripModel.
 // The WebContents started life as a ConstrainedWebDialog.
 // They get deleted when the printing finishes.
-class BackgroundPrintingManager : public base::NonThreadSafe,
-                                  public content::NotificationObserver {
+class BackgroundPrintingManager : public content::NotificationObserver {
  public:
   class Observer;
 
@@ -65,6 +64,8 @@
 
   content::NotificationRegistrar registrar_;
 
+  SEQUENCE_CHECKER(sequence_checker_);
+
   DISALLOW_COPY_AND_ASSIGN(BackgroundPrintingManager);
 };
 
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
index 03831e8d..309cbd0a 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
@@ -802,6 +802,7 @@
 TEST_F('BackgroundTest', 'ToggleButton', function() {
   var mockFeedback = this.createMockFeedback();
   this.runWithLoadedTree(function() {/*!
+    <div aria-pressed="mixed" role="button">boldface</div>
     <div aria-pressed="true" role="button">ok</div>
     <div aria-pressed="false" role="button">cancel</div>
     <div aria-pressed role="button">close</div>
@@ -809,6 +810,11 @@
     var b = ChromeVoxState.instance;
     var move = doCmd('nextObject');
     mockFeedback.call(move)
+        .expectSpeech('boldface')
+        .expectSpeech('Button')
+        .expectSpeech('Partially pressed')
+
+        .call(move)
         .expectSpeech('ok')
         .expectSpeech('Button')
         .expectSpeech('Pressed')
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js
index 2f37148..5d9e6611 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js
@@ -372,11 +372,6 @@
   disabled: {on: {msgId: 'aria_disabled_true'}},
   expanded: {on: {msgId: 'aria_expanded_true'}},
   multiselectable: {on: {msgId: 'aria_multiselectable_true'}},
-  pressed: {
-    isRoleSpecific: true,
-    on: {msgId: 'aria_pressed_true'},
-    off: {msgId: 'aria_pressed_false'}
-  },
   required: {on: {msgId: 'aria_required_true'}},
   selected: {on: {msgId: 'aria_selected_true'}},
   visited: {on: {msgId: 'visited_state'}}
@@ -398,6 +393,28 @@
 };
 
 /**
+ * Rules for mapping the checked property to a msg id
+ * @const {Object<string>}
+ * @private
+ */
+Output.CHECKED_STATE_MAP = {
+  'true': 'checked_true',
+  'false': 'checked_false',
+  'mixed': 'checked_mixed'
+};
+
+/**
+ * Rules for mapping the checked property to a msg id
+ * @const {Object<string>}
+ * @private
+ */
+Output.PRESSED_STATE_MAP = {
+  'true': 'aria_pressed_true',
+  'false': 'aria_pressed_false',
+  'mixed': 'aria_pressed_mixed'
+};
+
+/**
  * Rules specifying format of AutomationNodes for output.
  * @type {!Object<Object<Object<string>>>}
  */
@@ -586,7 +603,7 @@
       speak: '$nameFromNode $descendants $value $state $description'
     },
     toggleButton: {
-      speak: '$if($pressed, $earcon(CHECK_ON), $earcon(CHECK_OFF)) ' +
+      speak: '$if($checked, $earcon(CHECK_ON), $earcon(CHECK_OFF)) ' +
           '$name $role $pressed $description $state'
     },
     toolbar: {
@@ -1177,19 +1194,15 @@
             this.append_(buff, String(count));
           }
         } else if (token == 'checked') {
-          var msg;
-          switch (node.checked) {
-            case 'mixed':
-              msg = 'checked_mixed';
-              break;
-            case 'true':
-              msg = 'checked_true';
-              break;
-            default:
-              msg = 'checked_false';
-              break;
+          var msg = Output.CHECKED_STATE_MAP[node.checked];
+          if (msg) {
+            this.format_(node, '@' + msg, buff);
           }
-          this.format_(node, '@' + msg, buff);
+        } else if (token == 'pressed') {
+          var msg = Output.PRESSED_STATE_MAP[node.checked];
+          if (msg) {
+            this.format_(node, '@' + msg, buff);
+          }
         } else if (token == 'state') {
           if (node.state) {
             Object.getOwnPropertyNames(node.state).forEach(function(s) {
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output_test.extjs b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output_test.extjs
index 34c5622..f3c5b83 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output_test.extjs
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output_test.extjs
@@ -622,8 +622,7 @@
       assertEqualsJSON({string_: '|Subscribe|Button|Pressed', spans_: [
         {value: {earconId: 'CHECK_ON'}, start: 0, end: 0},
         {value: 'name', start: 1, end:10},
-        {value: 'role', start: 11, end: 17},
-        {value: 'state', start: 18, end: 25}
+        {value: 'role', start: 11, end: 17}
       ]}, o.speechOutputForTest);
   });
 });
diff --git a/chrome/browser/resources/chromeos/login/custom_elements_login.html b/chrome/browser/resources/chromeos/login/custom_elements_login.html
index c9353f7..7e0334d 100644
--- a/chrome/browser/resources/chromeos/login/custom_elements_login.html
+++ b/chrome/browser/resources/chromeos/login/custom_elements_login.html
@@ -1,3 +1,7 @@
+<!-- PIN keyboard is used outside of OOBE/login/lock so it includes the JS it
+     executes. This causes security errors if textually included here. -->
+<link rel="import" href="chrome://oobe/custom_elements/pin_keyboard.html">
+
 <include src="gaia_buttons.html">
 <include src="gaia_card.html">
 <include src="gaia_header.html">
diff --git a/chrome/browser/resources/chromeos/login/login.js b/chrome/browser/resources/chromeos/login/login.js
index bb83c78b..1ce1c5ec 100644
--- a/chrome/browser/resources/chromeos/login/login.js
+++ b/chrome/browser/resources/chromeos/login/login.js
@@ -12,6 +12,17 @@
 // <include src="login_non_lock_shared.js">
 // <include src="notification_card.js">
 
+/**
+ * Ensures that the pin keyboard is loaded.
+ * @param {object} onLoaded Callback executed when the pin keyboard is loaded.
+ */
+function ensurePinKeyboardLoaded(onLoaded) {
+  'use strict';
+
+  // Wait a frame before running |onLoaded| to avoid any visual glitches.
+  setTimeout(onLoaded);
+}
+
 cr.define('cr.ui.Oobe', function() {
   return {
     /**
diff --git a/chrome/browser/resources/chromeos/login/md_login.js b/chrome/browser/resources/chromeos/login/md_login.js
index cc899d30..e4e4e7d 100644
--- a/chrome/browser/resources/chromeos/login/md_login.js
+++ b/chrome/browser/resources/chromeos/login/md_login.js
@@ -12,6 +12,17 @@
 // <include src="login_non_lock_shared.js">
 // <include src="notification_card.js">
 
+/**
+ * Ensures that the pin keyboard is loaded.
+ * @param {object} onLoaded Callback executed when the pin keyboard is loaded.
+ */
+function ensurePinKeyboardLoaded(onLoaded) {
+  'use strict';
+
+  // Wait a frame before running |onLoaded| to avoid any visual glitches.
+  setTimeout(onLoaded);
+}
+
 cr.define('cr.ui.Oobe', function() {
   return {
     /**
diff --git a/chrome/browser/safe_browsing/certificate_reporting_service_test_utils.cc b/chrome/browser/safe_browsing/certificate_reporting_service_test_utils.cc
index f3c9d4c..85ce984 100644
--- a/chrome/browser/safe_browsing/certificate_reporting_service_test_utils.cc
+++ b/chrome/browser/safe_browsing/certificate_reporting_service_test_utils.cc
@@ -163,6 +163,7 @@
       weak_factory_(this) {}
 
 DelayableCertReportURLRequestJob::~DelayableCertReportURLRequestJob() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
                                    destruction_callback_);
 }
diff --git a/chrome/browser/safe_browsing/certificate_reporting_service_test_utils.h b/chrome/browser/safe_browsing/certificate_reporting_service_test_utils.h
index 4ac99fa..c6172da 100644
--- a/chrome/browser/safe_browsing/certificate_reporting_service_test_utils.h
+++ b/chrome/browser/safe_browsing/certificate_reporting_service_test_utils.h
@@ -9,7 +9,7 @@
 
 #include "base/macros.h"
 #include "base/run_loop.h"
-#include "base/threading/non_thread_safe.h"
+#include "base/sequence_checker.h"
 #include "chrome/browser/safe_browsing/certificate_reporting_service.h"
 #include "content/public/test/test_browser_thread.h"
 #include "content/public/test/test_browser_thread_bundle.h"
@@ -100,8 +100,7 @@
 // empty response. If Resume() is called before a request is made, then the
 // request will not be delayed. If not delayed, it can return a failed or a
 // successful URL request job.
-class DelayableCertReportURLRequestJob : public net::URLRequestJob,
-                                         public base::NonThreadSafe {
+class DelayableCertReportURLRequestJob : public net::URLRequestJob {
  public:
   DelayableCertReportURLRequestJob(
       bool delayed,
@@ -128,6 +127,9 @@
   bool should_fail_;
   bool started_;
   base::Callback<void()> destruction_callback_;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+
   base::WeakPtrFactory<DelayableCertReportURLRequestJob> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(DelayableCertReportURLRequestJob);
diff --git a/chrome/browser/safe_browsing/download_feedback.h b/chrome/browser/safe_browsing/download_feedback.h
index cd8adf5e..4789c47 100644
--- a/chrome/browser/safe_browsing/download_feedback.h
+++ b/chrome/browser/safe_browsing/download_feedback.h
@@ -11,7 +11,6 @@
 
 #include "base/callback_forward.h"
 #include "base/files/file_path.h"
-#include "base/threading/non_thread_safe.h"
 #include "chrome/browser/safe_browsing/two_phase_uploader.h"
 
 namespace safe_browsing {
@@ -20,7 +19,7 @@
 
 // Handles the uploading of a single downloaded binary to the safebrowsing
 // download feedback service.
-class DownloadFeedback : public base::NonThreadSafe {
+class DownloadFeedback {
  public:
   // Takes ownership of the file pointed to be |file_path|, it will be deleted
   // when the DownloadFeedback is destructed.
diff --git a/chrome/browser/safe_browsing/local_database_manager.cc b/chrome/browser/safe_browsing/local_database_manager.cc
index 12e93e48..99f3bbf8 100644
--- a/chrome/browser/safe_browsing/local_database_manager.cc
+++ b/chrome/browser/safe_browsing/local_database_manager.cc
@@ -427,6 +427,14 @@
   return database_->ContainsMalwareIP(ip_address);
 }
 
+AsyncMatch LocalSafeBrowsingDatabaseManager::CheckCsdWhitelistUrl(
+    const GURL& url,
+    Client* Client) {
+  // Pver3 DB does not support actual partial-hash whitelists, so we emulate
+  // it.  All this code will go away soon (~M62).
+  return (MatchCsdWhitelistUrl(url) ? AsyncMatch::MATCH : AsyncMatch::NO_MATCH);
+}
+
 bool LocalSafeBrowsingDatabaseManager::MatchCsdWhitelistUrl(const GURL& url) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   if (!enabled_ || !enable_csd_whitelist_ || !MakeDatabaseAvailable()) {
diff --git a/chrome/browser/safe_browsing/local_database_manager.h b/chrome/browser/safe_browsing/local_database_manager.h
index 185aa470..0ed5804c 100644
--- a/chrome/browser/safe_browsing/local_database_manager.h
+++ b/chrome/browser/safe_browsing/local_database_manager.h
@@ -126,6 +126,7 @@
   bool CheckExtensionIDs(const std::set<std::string>& extension_ids,
                          Client* client) override;
   bool CheckResourceUrl(const GURL& url, Client* client) override;
+  AsyncMatch CheckCsdWhitelistUrl(const GURL& url, Client* client) override;
   bool MatchCsdWhitelistUrl(const GURL& url) override;
   bool MatchMalwareIP(const std::string& ip_address) override;
   bool MatchDownloadWhitelistUrl(const GURL& url) override;
diff --git a/chrome/browser/safe_browsing/mojo_safe_browsing_impl.cc b/chrome/browser/safe_browsing/mojo_safe_browsing_impl.cc
new file mode 100644
index 0000000..08d61ca
--- /dev/null
+++ b/chrome/browser/safe_browsing/mojo_safe_browsing_impl.cc
@@ -0,0 +1,304 @@
+// Copyright 2017 The Chromium 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/safe_browsing/mojo_safe_browsing_impl.h"
+
+#include <vector>
+
+#include "base/memory/ptr_util.h"
+#include "base/memory/weak_ptr.h"
+#include "base/timer/timer.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/prerender/prerender_contents.h"
+#include "chrome/browser/safe_browsing/ui_manager.h"
+#include "components/safe_browsing_db/database_manager.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/resource_type.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "net/base/load_flags.h"
+
+namespace safe_browsing {
+namespace {
+
+// TODO(yzshen): Share such value with safe_browsing::BaseResourceThrottle.
+// Maximum time in milliseconds to wait for the SafeBrowsing service reputation
+// check. After this amount of time the outstanding check will be aborted, and
+// the resource will be treated as if it were safe.
+const int kCheckUrlTimeoutMs = 5000;
+
+content::WebContents* GetWebContentsFromID(int render_process_id,
+                                           int render_frame_id) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  content::RenderFrameHost* render_frame_host =
+      content::RenderFrameHost::FromID(render_process_id, render_frame_id);
+  if (!render_frame_host)
+    return nullptr;
+
+  return content::WebContents::FromRenderFrameHost(render_frame_host);
+}
+
+// TODO(yzshen): Handle the case where SafeBrowsing is not enabled, or
+// !database_manager()->IsSupported().
+// TODO(yzshen): Make sure it also works on Andorid.
+// TODO(yzshen): Do all the logging like what BaseResourceThrottle does.
+class SafeBrowsingUrlCheckerImpl : public chrome::mojom::SafeBrowsingUrlChecker,
+                                   public SafeBrowsingDatabaseManager::Client {
+ public:
+  SafeBrowsingUrlCheckerImpl(
+      int load_flags,
+      content::ResourceType resource_type,
+      scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
+      scoped_refptr<SafeBrowsingUIManager> ui_manager,
+      int render_process_id,
+      int render_frame_id)
+      : load_flags_(load_flags),
+        resource_type_(resource_type),
+        render_process_id_(render_process_id),
+        render_frame_id_(render_frame_id),
+        database_manager_(std::move(database_manager)),
+        ui_manager_(std::move(ui_manager)),
+        weak_factory_(this) {
+    DCHECK_NE(resource_type, content::RESOURCE_TYPE_MAIN_FRAME);
+    DCHECK_NE(resource_type, content::RESOURCE_TYPE_SUB_FRAME);
+  }
+
+  ~SafeBrowsingUrlCheckerImpl() override {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+    if (state_ == STATE_CHECKING_URL)
+      database_manager_->CancelCheck(this);
+
+    for (size_t i = next_index_; i < callbacks_.size(); ++i)
+      std::move(callbacks_[i]).Run(false);
+  }
+
+  // chrome::mojom::SafeBrowsingUrlChecker implementation.
+  void CheckUrl(const GURL& url, CheckUrlCallback callback) override {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+    DVLOG(1) << "SafeBrowsingUrlCheckerImpl checks URL: " << url;
+    urls_.push_back(url);
+    callbacks_.push_back(std::move(callback));
+
+    ProcessUrls();
+  }
+
+ private:
+  // SafeBrowsingDatabaseManager::Client implementation:
+  void OnCheckBrowseUrlResult(const GURL& url,
+                              SBThreatType threat_type,
+                              const ThreatMetadata& metadata) override {
+    DCHECK_EQ(STATE_CHECKING_URL, state_);
+    DCHECK_LT(next_index_, urls_.size());
+    DCHECK_EQ(urls_[next_index_], url);
+
+    timer_.Stop();
+    if (threat_type == SB_THREAT_TYPE_SAFE) {
+      state_ = STATE_NONE;
+      std::move(callbacks_[next_index_]).Run(true);
+      next_index_++;
+      ProcessUrls();
+      return;
+    }
+
+    if (load_flags_ & net::LOAD_PREFETCH) {
+      BlockAndProcessUrls();
+      return;
+    }
+
+    security_interstitials::UnsafeResource resource;
+    resource.url = url;
+    resource.original_url = urls_[0];
+    if (urls_.size() > 1)
+      resource.redirect_urls =
+          std::vector<GURL>(urls_.begin() + 1, urls_.end());
+    resource.is_subresource = true;
+    resource.is_subframe = false;
+    resource.threat_type = threat_type;
+    resource.threat_metadata = metadata;
+    resource.callback =
+        base::Bind(&SafeBrowsingUrlCheckerImpl::OnBlockingPageComplete,
+                   weak_factory_.GetWeakPtr());
+    resource.callback_thread = content::BrowserThread::GetTaskRunnerForThread(
+        content::BrowserThread::IO);
+    resource.web_contents_getter =
+        base::Bind(&GetWebContentsFromID, render_process_id_, render_frame_id_);
+    resource.threat_source = database_manager_->GetThreatSource();
+
+    state_ = STATE_DISPLAYING_BLOCKING_PAGE;
+
+    content::BrowserThread::PostTask(
+        content::BrowserThread::UI, FROM_HERE,
+        base::Bind(&SafeBrowsingUrlCheckerImpl::StartDisplayingBlockingPage,
+                   weak_factory_.GetWeakPtr(), ui_manager_, resource));
+  }
+
+  static void StartDisplayingBlockingPage(
+      const base::WeakPtr<SafeBrowsingUrlCheckerImpl>& checker,
+      scoped_refptr<BaseUIManager> ui_manager,
+      const security_interstitials::UnsafeResource& resource) {
+    content::WebContents* web_contents = resource.web_contents_getter.Run();
+    if (web_contents) {
+      prerender::PrerenderContents* prerender_contents =
+          prerender::PrerenderContents::FromWebContents(web_contents);
+      if (prerender_contents) {
+        prerender_contents->Destroy(prerender::FINAL_STATUS_SAFE_BROWSING);
+      } else {
+        ui_manager->DisplayBlockingPage(resource);
+        return;
+      }
+    }
+
+    // Tab is gone or it's being prerendered.
+    content::BrowserThread::PostTask(
+        content::BrowserThread::IO, FROM_HERE,
+        base::BindOnce(&SafeBrowsingUrlCheckerImpl::BlockAndProcessUrls,
+                       checker));
+  }
+
+  void OnCheckUrlTimeout() {
+    database_manager_->CancelCheck(this);
+
+    OnCheckBrowseUrlResult(urls_[next_index_],
+                           safe_browsing::SB_THREAT_TYPE_SAFE,
+                           ThreatMetadata());
+  }
+
+  void ProcessUrls() {
+    DCHECK_NE(STATE_BLOCKED, state_);
+
+    if (state_ == STATE_CHECKING_URL ||
+        state_ == STATE_DISPLAYING_BLOCKING_PAGE) {
+      return;
+    }
+
+    while (next_index_ < urls_.size()) {
+      DCHECK_EQ(STATE_NONE, state_);
+      // TODO(yzshen): Consider moving CanCheckResourceType() to the renderer
+      // side. That would save some IPCs. It requires a method on the
+      // SafeBrowsing mojo interface to query all supported resource types.
+      if (!database_manager_->CanCheckResourceType(resource_type_) ||
+          database_manager_->CheckBrowseUrl(urls_[next_index_], this)) {
+        std::move(callbacks_[next_index_]).Run(true);
+        next_index_++;
+        continue;
+      }
+
+      state_ = STATE_CHECKING_URL;
+      // Start a timer to abort the check if it takes too long.
+      timer_.Start(FROM_HERE,
+                   base::TimeDelta::FromMilliseconds(kCheckUrlTimeoutMs), this,
+                   &SafeBrowsingUrlCheckerImpl::OnCheckUrlTimeout);
+
+      break;
+    }
+  }
+
+  void BlockAndProcessUrls() {
+    DVLOG(1) << "SafeBrowsingUrlCheckerImpl blocks URL: " << urls_[next_index_];
+    state_ = STATE_BLOCKED;
+
+    // If user decided to not proceed through a warning, mark all the remaining
+    // redirects as "bad".
+    for (; next_index_ < callbacks_.size(); ++next_index_)
+      std::move(callbacks_[next_index_]).Run(false);
+  }
+
+  void OnBlockingPageComplete(bool proceed) {
+    DCHECK_EQ(STATE_DISPLAYING_BLOCKING_PAGE, state_);
+
+    if (proceed) {
+      state_ = STATE_NONE;
+      std::move(callbacks_[next_index_]).Run(true);
+      next_index_++;
+      ProcessUrls();
+    } else {
+      BlockAndProcessUrls();
+    }
+  }
+
+  enum State {
+    // Haven't started checking or checking is complete.
+    STATE_NONE,
+    // We have one outstanding URL-check.
+    STATE_CHECKING_URL,
+    // We're displaying a blocking page.
+    STATE_DISPLAYING_BLOCKING_PAGE,
+    // The blocking page has returned *not* to proceed.
+    STATE_BLOCKED
+  };
+
+  const int load_flags_;
+  const content::ResourceType resource_type_;
+  const int render_process_id_;
+  const int render_frame_id_;
+  scoped_refptr<SafeBrowsingDatabaseManager> database_manager_;
+  scoped_refptr<BaseUIManager> ui_manager_;
+
+  // The redirect chain for this resource, including the original URL and
+  // subsequent redirect URLs.
+  std::vector<GURL> urls_;
+  // Callbacks corresponding to |urls_| to report check results. |urls_| and
+  // |callbacks_| are always of the same size.
+  std::vector<CheckUrlCallback> callbacks_;
+  // |urls_| before |next_index_| have been checked. If |next_index_| is smaller
+  // than the size of |urls_|, the URL at |next_index_| is being processed.
+  size_t next_index_ = 0;
+
+  State state_ = STATE_NONE;
+
+  // Timer to abort the SafeBrowsing check if it takes too long.
+  base::OneShotTimer timer_;
+
+  base::WeakPtrFactory<SafeBrowsingUrlCheckerImpl> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(SafeBrowsingUrlCheckerImpl);
+};
+
+}  // namespace
+
+MojoSafeBrowsingImpl::MojoSafeBrowsingImpl(
+    scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
+    scoped_refptr<SafeBrowsingUIManager> ui_manager,
+    int render_process_id)
+    : database_manager_(std::move(database_manager)),
+      ui_manager_(std::move(ui_manager)),
+      render_process_id_(render_process_id) {}
+
+MojoSafeBrowsingImpl::~MojoSafeBrowsingImpl() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+}
+
+// static
+void MojoSafeBrowsingImpl::Create(
+    scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
+    scoped_refptr<SafeBrowsingUIManager> ui_manager,
+    int render_process_id,
+    const service_manager::BindSourceInfo& source_info,
+    chrome::mojom::SafeBrowsingRequest request) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  mojo::MakeStrongBinding(base::MakeUnique<MojoSafeBrowsingImpl>(
+                              std::move(database_manager),
+                              std::move(ui_manager), render_process_id),
+                          std::move(request));
+}
+
+void MojoSafeBrowsingImpl::CreateCheckerAndCheck(
+    int32_t render_frame_id,
+    chrome::mojom::SafeBrowsingUrlCheckerRequest request,
+    const GURL& url,
+    int32_t load_flags,
+    content::ResourceType resource_type,
+    CreateCheckerAndCheckCallback callback) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  auto checker_impl = base::MakeUnique<SafeBrowsingUrlCheckerImpl>(
+      static_cast<int>(load_flags), resource_type, database_manager_,
+      ui_manager_, render_process_id_, static_cast<int>(render_frame_id));
+  checker_impl->CheckUrl(url, std::move(callback));
+  mojo::MakeStrongBinding(std::move(checker_impl), std::move(request));
+}
+
+}  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/mojo_safe_browsing_impl.h b/chrome/browser/safe_browsing/mojo_safe_browsing_impl.h
new file mode 100644
index 0000000..d7b8e11
--- /dev/null
+++ b/chrome/browser/safe_browsing/mojo_safe_browsing_impl.h
@@ -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.
+
+#ifndef CHROME_BROWSER_SAFE_BROWSING_MOJO_SAFE_BROWSING_IMPL_H_
+#define CHROME_BROWSER_SAFE_BROWSING_MOJO_SAFE_BROWSING_IMPL_H_
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "chrome/browser/safe_browsing/ui_manager.h"
+#include "chrome/common/safe_browsing.mojom.h"
+#include "components/safe_browsing_db/database_manager.h"
+#include "ipc/ipc_message.h"
+
+namespace service_manager {
+struct BindSourceInfo;
+}
+
+namespace safe_browsing {
+
+// This class implements the Mojo interface for renderers to perform
+// SafeBrowsing URL checks.
+class MojoSafeBrowsingImpl : public chrome::mojom::SafeBrowsing {
+ public:
+  MojoSafeBrowsingImpl(
+      scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
+      scoped_refptr<SafeBrowsingUIManager> ui_manager,
+      int render_process_id);
+  ~MojoSafeBrowsingImpl() override;
+
+  static void Create(
+      scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
+      scoped_refptr<SafeBrowsingUIManager> ui_manager,
+      int render_process_id,
+      const service_manager::BindSourceInfo& source_info,
+      chrome::mojom::SafeBrowsingRequest request);
+
+ private:
+  // chrome::mojom::SafeBrowsing implementation.
+  void CreateCheckerAndCheck(
+      int32_t render_frame_id,
+      chrome::mojom::SafeBrowsingUrlCheckerRequest request,
+      const GURL& url,
+      int32_t load_flags,
+      content::ResourceType resource_type,
+      CreateCheckerAndCheckCallback callback) override;
+
+  scoped_refptr<SafeBrowsingDatabaseManager> database_manager_;
+  scoped_refptr<SafeBrowsingUIManager> ui_manager_;
+  int render_process_id_ = MSG_ROUTING_NONE;
+
+  DISALLOW_COPY_AND_ASSIGN(MojoSafeBrowsingImpl);
+};
+
+}  // namespace safe_browsing
+
+#endif  // CHROME_BROWSER_SAFE_BROWSING_MOJO_SAFE_BROWSING_IMPL_H_
diff --git a/chrome/browser/shell_integration.cc b/chrome/browser/shell_integration.cc
index e18e93ea..61a3bbf 100644
--- a/chrome/browser/shell_integration.cc
+++ b/chrome/browser/shell_integration.cc
@@ -45,18 +45,6 @@
 
 const struct AppModeInfo* gAppModeInfo = nullptr;
 
-scoped_refptr<base::SequencedTaskRunner>
-CreateTaskRunnerForDefaultWebClientWorker() {
-#if defined(OS_WIN)
-  if (base::win::GetVersion() >= base::win::VERSION_WIN10)
-    // TODO(pmonette): Windows 10's implementation uses a base::Timer which
-    // currently still requires a SingleThreadTaskRunner. Change this to a
-    // SequencedTaskRunner when crbug.com/552633 is fixed.
-    return base::CreateSingleThreadTaskRunnerWithTraits({base::MayBlock()});
-#endif  // defined(OS_WIN)
-  return base::CreateSequencedTaskRunnerWithTraits({base::MayBlock()});
-}
-
 }  // namespace
 
 bool CanSetAsDefaultBrowser() {
@@ -194,7 +182,7 @@
 
   if (!task_runner) {
     task_runner = new scoped_refptr<base::SequencedTaskRunner>(
-        CreateTaskRunnerForDefaultWebClientWorker());
+        base::CreateSequencedTaskRunnerWithTraits({base::MayBlock()}));
   }
 
   return *task_runner;
diff --git a/chrome/browser/signin/easy_unlock_app_manager.cc b/chrome/browser/signin/easy_unlock_app_manager.cc
index 29e7e20..50327f1 100644
--- a/chrome/browser/signin/easy_unlock_app_manager.cc
+++ b/chrome/browser/signin/easy_unlock_app_manager.cc
@@ -79,11 +79,9 @@
 }
 
 void EasyUnlockAppManagerImpl::LaunchSetup() {
-  PA_LOG(WARNING) << "LaunchSetup()";
   ExtensionService* extension_service = extension_system_->extension_service();
   if (!extension_service)
     return;
-  PA_LOG(WARNING) << "got extension service";
 
   const extensions::Extension* extension =
       extension_service->GetExtensionById(app_id_, false);
@@ -92,7 +90,6 @@
     return;
   }
 
-  PA_LOG(WARNING) << "launching app...";
   OpenApplication(AppLaunchParams(extension_service->profile(), extension,
                                   extensions::LAUNCH_CONTAINER_WINDOW,
                                   WindowOpenDisposition::NEW_WINDOW,
diff --git a/chrome/browser/signin/easy_unlock_service_regular.cc b/chrome/browser/signin/easy_unlock_service_regular.cc
index 8c4dbd6..496a8b9c 100644
--- a/chrome/browser/signin/easy_unlock_service_regular.cc
+++ b/chrome/browser/signin/easy_unlock_service_regular.cc
@@ -443,7 +443,6 @@
 }
 
 void EasyUnlockServiceRegular::InitializeInternal() {
-  PA_LOG(INFO) << "Initializing EasyUnlockService inside the user session.";
   proximity_auth::ScreenlockBridge::Get()->AddObserver(this);
   registrar_.Init(profile()->GetPrefs());
   registrar_.Add(
diff --git a/chrome/browser/ssl/security_state_tab_helper.cc b/chrome/browser/ssl/security_state_tab_helper.cc
index a5c7c94..82a9e62 100644
--- a/chrome/browser/ssl/security_state_tab_helper.cc
+++ b/chrome/browser/ssl/security_state_tab_helper.cc
@@ -179,6 +179,7 @@
       case safe_browsing::SB_THREAT_TYPE_BLACKLISTED_RESOURCE:
       case safe_browsing::SB_THREAT_TYPE_API_ABUSE:
       case safe_browsing::SB_THREAT_TYPE_SUBRESOURCE_FILTER:
+      case safe_browsing::SB_THREAT_TYPE_CSD_WHITELIST:
         // These threat types are not currently associated with
         // interstitials, and thus resources with these threat types are
         // not ever whitelisted or pending whitelisting.
diff --git a/chrome/browser/sync/user_event_service_factory.cc b/chrome/browser/sync/user_event_service_factory.cc
index de35956..bcf784e0 100644
--- a/chrome/browser/sync/user_event_service_factory.cc
+++ b/chrome/browser/sync/user_event_service_factory.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "base/memory/ptr_util.h"
+#include "chrome/browser/profiles/incognito_helpers.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/common/channel_info.h"
@@ -15,7 +16,8 @@
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/sync/base/model_type.h"
 #include "components/sync/base/report_unrecoverable_error.h"
-#include "components/sync/user_events/user_event_service.h"
+#include "components/sync/user_events/no_op_user_event_service.h"
+#include "components/sync/user_events/user_event_service_impl.h"
 #include "components/sync/user_events/user_event_sync_bridge.h"
 
 namespace browser_sync {
@@ -41,6 +43,10 @@
 
 KeyedService* UserEventServiceFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
+  if (context->IsOffTheRecord()) {
+    return new syncer::NoOpUserEventService();
+  }
+
   Profile* profile = Profile::FromBrowserContext(context);
   syncer::ModelTypeStoreFactory store_factory =
       browser_sync::ProfileSyncService::GetModelTypeStoreFactory(
@@ -51,8 +57,13 @@
                                               chrome::GetChannel()));
   auto bridge = base::MakeUnique<syncer::UserEventSyncBridge>(
       std::move(store_factory), std::move(processor_factory));
-  return new syncer::UserEventService(
+  return new syncer::UserEventServiceImpl(
       ProfileSyncServiceFactory::GetForProfile(profile), std::move(bridge));
 }
 
+content::BrowserContext* UserEventServiceFactory::GetBrowserContextToUse(
+    content::BrowserContext* context) const {
+  return chrome::GetBrowserContextOwnInstanceInIncognito(context);
+}
+
 }  // namespace browser_sync
diff --git a/chrome/browser/sync/user_event_service_factory.h b/chrome/browser/sync/user_event_service_factory.h
index 0cc9806..26d2b444 100644
--- a/chrome/browser/sync/user_event_service_factory.h
+++ b/chrome/browser/sync/user_event_service_factory.h
@@ -31,6 +31,8 @@
   // BrowserContextKeyedServiceFactory:
   KeyedService* BuildServiceInstanceFor(
       content::BrowserContext* context) const override;
+  content::BrowserContext* GetBrowserContextToUse(
+      content::BrowserContext* context) const override;
 
   DISALLOW_COPY_AND_ASSIGN(UserEventServiceFactory);
 };
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 56b832f..630148f 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -879,8 +879,6 @@
       "task_manager/task_manager_columns.h",
       "task_manager/task_manager_table_model.cc",
       "task_manager/task_manager_table_model.h",
-      "toolbar/app_menu_animation.cc",
-      "toolbar/app_menu_animation.h",
       "toolbar/app_menu_icon_controller.cc",
       "toolbar/app_menu_icon_controller.h",
       "toolbar/app_menu_model.cc",
diff --git a/chrome/browser/ui/toolbar/app_menu_animation.cc b/chrome/browser/ui/toolbar/app_menu_animation.cc
deleted file mode 100644
index bb4d3153..0000000
--- a/chrome/browser/ui/toolbar/app_menu_animation.cc
+++ /dev/null
@@ -1,189 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/toolbar/app_menu_animation.h"
-
-#include "base/memory/ptr_util.h"
-#include "cc/paint/paint_flags.h"
-#include "ui/gfx/animation/tween.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/color_palette.h"
-#include "ui/gfx/color_utils.h"
-#include "ui/gfx/skia_util.h"
-
-namespace {
-
-// Duration of the open and close animations in ms.
-constexpr float kOpenDurationMs = 733.0f;
-constexpr float kCloseDurationMs = 283.0f;
-
-// Duration of the color animation in ms.
-constexpr float kColorDurationMs = 100.0f;
-
-// The radius of each dot in the icon.
-constexpr float kDotRadius = 2.0f;
-
-// The % the top and bottom dots need to be offset from the middle.
-constexpr float kDotYOffset = 0.32f;
-
-// Value of the stroke when the icon is opened or closed.
-constexpr float kCloseStroke = 0.204f;
-constexpr float kOpenStroke = 0.136f;
-
-// Value of the width when the animation is fully opened.
-constexpr float kOpenWidth = 0.52f;
-
-// The delay of the color and dot animations in ms.
-constexpr float kColorDelayMs = 33.33f;
-constexpr float kDotDelayMs = 66.67f;
-
-// The % of time it takes for each dot to animate to its full width.
-constexpr float kTopWidthOpenInterval = 533.3f / kOpenDurationMs;
-constexpr float kMiddleWidthOpenInterval = 383.3f / kOpenDurationMs;
-constexpr float kBottomWidthOpenInterval = 400.0f / kOpenDurationMs;
-
-// The % of time it takes for each dot to animate to its final stroke.
-constexpr float kTopStrokeOpenInterval = 400.0f / kOpenDurationMs;
-constexpr float kMiddleStrokeOpenInterval = 283.3f / kOpenDurationMs;
-constexpr float kBottomStrokeOpenInterval = 266.7f / kOpenDurationMs;
-
-// The % of time it takes for each dot to animate its width and stroke.
-constexpr float kWidthStrokeCloseInterval = 150.0f / kCloseDurationMs;
-
-}  // namespace
-
-AppMenuAnimation::AppMenuDot::AppMenuDot(base::TimeDelta delay,
-                                         float width_open_interval,
-                                         float stroke_open_interval)
-    : delay_(delay),
-      width_open_interval_(width_open_interval),
-      stroke_open_interval_(stroke_open_interval) {}
-
-void AppMenuAnimation::AppMenuDot::Paint(const gfx::PointF& center_point,
-                                         SkColor start_color,
-                                         SkColor target_color,
-                                         gfx::Canvas* canvas,
-                                         const gfx::Rect& bounds,
-                                         const gfx::SlideAnimation* animation,
-                                         AppMenuAnimationDelegate* delegate) {
-  bool is_opening = animation->IsShowing();
-  float total_duration = is_opening ? kOpenDurationMs : kCloseDurationMs;
-  float width_duration =
-      is_opening ? width_open_interval_ : kWidthStrokeCloseInterval;
-  float stroke_duration =
-      is_opening ? stroke_open_interval_ : kWidthStrokeCloseInterval;
-
-  // When the animation is closing, each dot uses the remainder of the full
-  // delay period (2 * kDotDelayMs). The results should be (0->2x, 1x->1x,
-  // 2x->0).
-  base::TimeDelta delay =
-      is_opening ? delay_
-                 : base::TimeDelta::FromMilliseconds(kDotDelayMs * 2) - delay_;
-  float progress =
-      animation->GetCurrentValue() - (delay.InMillisecondsF() / total_duration);
-
-  float width_progress = 0.0;
-  float stroke_progress = 0.0;
-  float color_progress = 0.0;
-
-  if (progress > 0) {
-    width_progress = std::min(1.0f, progress / width_duration);
-    stroke_progress = std::min(1.0f, progress / stroke_duration);
-
-    if (is_opening) {
-      float color_delay_interval = kColorDelayMs / total_duration;
-      float color_duration_interval = kColorDurationMs / total_duration;
-      if (progress > color_delay_interval) {
-        color_progress = std::min(
-            1.0f, (progress - color_delay_interval) / color_duration_interval);
-      }
-    }
-  }
-
-  float dot_height =
-      gfx::Tween::FloatValueBetween(stroke_progress, kCloseStroke, kOpenStroke);
-  dot_height *= bounds.height();
-
-  float dot_width =
-      gfx::Tween::FloatValueBetween(width_progress, kCloseStroke, kOpenWidth);
-  dot_width *= bounds.width();
-
-  gfx::PointF point = center_point;
-  point.Offset(-dot_width / 2, -dot_height / 2);
-
-  SkColor color = is_opening ? gfx::Tween::ColorValueBetween(
-                                   color_progress, start_color, target_color)
-                             : target_color;
-
-  cc::PaintFlags flags;
-  flags.setColor(color);
-  flags.setStrokeWidth(dot_height);
-  flags.setStrokeCap(cc::PaintFlags::kRound_Cap);
-  flags.setStyle(cc::PaintFlags::kFill_Style);
-  flags.setAntiAlias(true);
-  canvas->DrawRoundRect(gfx::RectF(point, gfx::SizeF(dot_width, dot_height)),
-                        kDotRadius, flags);
-}
-
-AppMenuAnimation::AppMenuAnimation(AppMenuAnimationDelegate* delegate,
-                                   SkColor initial_color)
-    : delegate_(delegate),
-      animation_(base::MakeUnique<gfx::SlideAnimation>(this)),
-      bottom_dot_(base::TimeDelta(),
-                  kBottomWidthOpenInterval,
-                  kBottomStrokeOpenInterval),
-      middle_dot_(base::TimeDelta::FromMilliseconds(kDotDelayMs),
-                  kMiddleWidthOpenInterval,
-                  kMiddleStrokeOpenInterval),
-      top_dot_(base::TimeDelta::FromMilliseconds(kDotDelayMs * 2),
-               kTopWidthOpenInterval,
-               kTopStrokeOpenInterval),
-      start_color_(initial_color),
-      target_color_(initial_color) {
-  animation_->SetSlideDuration(kOpenDurationMs);
-  animation_->SetTweenType(gfx::Tween::FAST_OUT_SLOW_IN);
-}
-
-AppMenuAnimation::~AppMenuAnimation() {}
-
-void AppMenuAnimation::PaintAppMenu(gfx::Canvas* canvas,
-                                    const gfx::Rect& bounds) {
-  gfx::PointF middle_point = gfx::PointF(bounds.CenterPoint());
-  float y_offset = kDotYOffset * bounds.height();
-  gfx::PointF top_point = middle_point;
-  top_point.Offset(0, -y_offset);
-
-  gfx::PointF bottom_point = middle_point;
-  bottom_point.Offset(0, y_offset);
-
-  middle_dot_.Paint(middle_point, start_color_, target_color_, canvas, bounds,
-                    animation_.get(), delegate_);
-  top_dot_.Paint(top_point, start_color_, target_color_, canvas, bounds,
-                 animation_.get(), delegate_);
-  bottom_dot_.Paint(bottom_point, start_color_, target_color_, canvas, bounds,
-                    animation_.get(), delegate_);
-}
-
-void AppMenuAnimation::StartAnimation() {
-  if (!animation_->is_animating()) {
-    animation_->SetSlideDuration(kOpenDurationMs);
-    animation_->Show();
-    delegate_->AppMenuAnimationStarted();
-  }
-}
-
-void AppMenuAnimation::AnimationEnded(const gfx::Animation* animation) {
-  if (animation_->IsShowing()) {
-    animation_->SetSlideDuration(kCloseDurationMs);
-    animation_->Hide();
-  } else {
-    start_color_ = target_color_;
-  }
-
-  delegate_->AppMenuAnimationEnded();
-}
-
-void AppMenuAnimation::AnimationProgressed(const gfx::Animation* animation) {
-  delegate_->InvalidateIcon();
-}
diff --git a/chrome/browser/ui/toolbar/app_menu_animation.h b/chrome/browser/ui/toolbar/app_menu_animation.h
deleted file mode 100644
index 2f93834..0000000
--- a/chrome/browser/ui/toolbar/app_menu_animation.h
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_TOOLBAR_APP_MENU_ANIMATION_H_
-#define CHROME_BROWSER_UI_TOOLBAR_APP_MENU_ANIMATION_H_
-
-#include "base/time/time.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "ui/gfx/animation/animation_delegate.h"
-#include "ui/gfx/animation/slide_animation.h"
-
-namespace gfx {
-class Canvas;
-class PointF;
-}  // namespace gfx
-
-// Delegate class for AppMenuAnimation. The delegate is expected to
-// handle animation events and invalidate the platform's view.
-class AppMenuAnimationDelegate {
- public:
-  // Called when the animation has started/ended.
-  virtual void AppMenuAnimationStarted() = 0;
-  virtual void AppMenuAnimationEnded() = 0;
-
-  // Schedules a redraw of the icon.
-  virtual void InvalidateIcon() = 0;
-};
-
-// This class is used for animating and drawing the app menu icon.
-class AppMenuAnimation : public gfx::AnimationDelegate {
- public:
-  AppMenuAnimation(AppMenuAnimationDelegate* owner, SkColor initial_color);
-
-  ~AppMenuAnimation() override;
-
-  // Paints the app menu icon.
-  void PaintAppMenu(gfx::Canvas* canvas, const gfx::Rect& bounds);
-
-  // Starts the animation if it's not already running.
-  void StartAnimation();
-
-  // gfx::AnimationDelegate:
-  void AnimationEnded(const gfx::Animation* animation) override;
-  void AnimationProgressed(const gfx::Animation* animation) override;
-
-  void set_target_color(SkColor target_color) { target_color_ = target_color; }
-
- private:
-  // This class is used to represent and paint a dot on the app menu.
-  class AppMenuDot {
-   public:
-    AppMenuDot(base::TimeDelta delay,
-               float width_open_interval,
-               float stroke_open_interval);
-
-    // Paints the dot on the given |canvas| according to the progress of
-    // |animation|. The size of the dot is calculated to fit in |bounds|.
-    // |center_point| is the dot's position on the canvas. The dot's color is
-    // a transition from |start_color| to |final_color|.
-    void Paint(const gfx::PointF& center_point,
-               SkColor start_color,
-               SkColor final_color,
-               gfx::Canvas* canvas,
-               const gfx::Rect& bounds,
-               const gfx::SlideAnimation* animation,
-               AppMenuAnimationDelegate* delegate);
-
-   private:
-    // The delay before the dot starts animating in ms.
-    const base::TimeDelta delay_;
-
-    // The percentage of the overall animation duration it takes to animate the
-    // width and stroke to their open state.
-    const float width_open_interval_;
-    const float stroke_open_interval_;
-
-    DISALLOW_COPY_AND_ASSIGN(AppMenuDot);
-  };
-
-  AppMenuAnimationDelegate* const delegate_;
-
-  std::unique_ptr<gfx::SlideAnimation> animation_;
-
-  AppMenuDot bottom_dot_;
-  AppMenuDot middle_dot_;
-  AppMenuDot top_dot_;
-
-  // The starting color of the dots. The animation is expected to transition
-  // from this color to |target_color_|.
-  SkColor start_color_;
-
-  // The severity color of the dots. This is final color at the end of the
-  // animation.
-  SkColor target_color_;
-
-  DISALLOW_COPY_AND_ASSIGN(AppMenuAnimation);
-};
-
-#endif  // CHROME_BROWSER_UI_TOOLBAR_APP_MENU_ANIMATION_H_
diff --git a/chrome/browser/ui/views/status_icons/status_tray_state_changer_win.cc b/chrome/browser/ui/views/status_icons/status_tray_state_changer_win.cc
index 1cbb729..432b976 100644
--- a/chrome/browser/ui/views/status_icons/status_tray_state_changer_win.cc
+++ b/chrome/browser/ui/views/status_icons/status_tray_state_changer_win.cc
@@ -62,7 +62,7 @@
 }
 
 void StatusTrayStateChangerWin::EnsureTrayIconVisible() {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   if (!CreateTrayNotify()) {
     VLOG(1) << "Unable to create COM object for ITrayNotify.";
@@ -86,18 +86,18 @@
 }
 
 STDMETHODIMP_(ULONG) StatusTrayStateChangerWin::AddRef() {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   return base::win::IUnknownImpl::AddRef();
 }
 
 STDMETHODIMP_(ULONG) StatusTrayStateChangerWin::Release() {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   return base::win::IUnknownImpl::Release();
 }
 
 STDMETHODIMP StatusTrayStateChangerWin::QueryInterface(REFIID riid,
                                                        PVOID* ptr_void) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   if (riid == __uuidof(INotificationCB)) {
     *ptr_void = static_cast<INotificationCB*>(this);
     AddRef();
@@ -109,7 +109,7 @@
 
 STDMETHODIMP StatusTrayStateChangerWin::Notify(ULONG event,
                                                NOTIFYITEM* notify_item) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(notify_item);
   if (notify_item->hwnd != window_ || notify_item->id != icon_id_ ||
       base::string16(notify_item->exe_name) != file_name_) {
@@ -121,11 +121,11 @@
 }
 
 StatusTrayStateChangerWin::~StatusTrayStateChangerWin() {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 }
 
 bool StatusTrayStateChangerWin::CreateTrayNotify() {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   tray_notify_.Reset();  // Reset so this method can be called more than once.
 
diff --git a/chrome/browser/ui/views/status_icons/status_tray_state_changer_win.h b/chrome/browser/ui/views/status_icons/status_tray_state_changer_win.h
index 75ee678..310b117 100644
--- a/chrome/browser/ui/views/status_icons/status_tray_state_changer_win.h
+++ b/chrome/browser/ui/views/status_icons/status_tray_state_changer_win.h
@@ -9,7 +9,7 @@
 
 #include "base/macros.h"
 #include "base/strings/string16.h"
-#include "base/threading/non_thread_safe.h"
+#include "base/threading/thread_checker.h"
 #include "base/win/iunknown_impl.h"
 #include "base/win/scoped_comptr.h"
 
@@ -53,8 +53,7 @@
 // overflow area to the taskbar, and refuses to do anything if the user has
 // explicitly marked an icon to be always hidden.
 class StatusTrayStateChangerWin : public INotificationCB,
-                                  public base::win::IUnknownImpl,
-                                  public base::NonThreadSafe {
+                                  public base::win::IUnknownImpl {
  public:
   StatusTrayStateChangerWin(UINT icon_id, HWND window);
 
@@ -129,6 +128,8 @@
   // so we can't just return the notifyitem we're looking for.
   std::unique_ptr<NOTIFYITEM> notify_item_;
 
+  THREAD_CHECKER(thread_checker_);
+
   DISALLOW_COPY_AND_ASSIGN(StatusTrayStateChangerWin);
 };
 
diff --git a/chrome/browser/ui/views/status_icons/status_tray_win.cc b/chrome/browser/ui/views/status_icons/status_tray_win.cc
index 511a1ea..c9693a5 100644
--- a/chrome/browser/ui/views/status_icons/status_tray_win.cc
+++ b/chrome/browser/ui/views/status_icons/status_tray_win.cc
@@ -12,8 +12,8 @@
 #include "base/location.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
+#include "base/sequence_checker.h"
 #include "base/single_thread_task_runner.h"
-#include "base/threading/non_thread_safe.h"
 #include "base/threading/thread.h"
 #include "base/win/wrapped_window_proc.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
@@ -40,8 +40,7 @@
 // Exporer.exe via COM.  It spawns a background thread with a fresh COM
 // apartment and requests that the visibility be increased unless the user
 // has explicitly set the icon to be hidden.
-class StatusTrayStateChangerProxyImpl : public StatusTrayStateChangerProxy,
-                                        public base::NonThreadSafe {
+class StatusTrayStateChangerProxyImpl : public StatusTrayStateChangerProxy {
  public:
   StatusTrayStateChangerProxyImpl()
       : pending_requests_(0),
@@ -50,8 +49,12 @@
     worker_thread_.init_com_with_mta(false);
   }
 
+  ~StatusTrayStateChangerProxyImpl() override {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  }
+
   void EnqueueChange(UINT icon_id, HWND window) override {
-    DCHECK(CalledOnValidThread());
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     if (pending_requests_ == 0)
       worker_thread_.Start();
 
@@ -80,7 +83,7 @@
 
   // Called on UI thread.
   void ChangeDone() {
-    DCHECK(CalledOnValidThread());
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     DCHECK_GT(pending_requests_, 0);
 
     if (--pending_requests_ == 0)
@@ -90,6 +93,9 @@
  private:
   int pending_requests_;
   base::Thread worker_thread_;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+
   base::WeakPtrFactory<StatusTrayStateChangerProxyImpl> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(StatusTrayStateChangerProxyImpl);
diff --git a/chrome/browser/ui/views/tabs/stacked_tab_strip_layout.cc b/chrome/browser/ui/views/tabs/stacked_tab_strip_layout.cc
index 71b6a52..d522404 100644
--- a/chrome/browser/ui/views/tabs/stacked_tab_strip_layout.cc
+++ b/chrome/browser/ui/views/tabs/stacked_tab_strip_layout.cc
@@ -87,7 +87,7 @@
     AdjustStackedTabs();
   } else if (delta < 0 && initial_x == GetMaxX(active_index())) {
     LayoutByTabOffsetBefore(active_index());
-    ResetToIdealState();
+    AdjustStackedTabs();
   }
   int x = delta > 0 ?
       std::min(initial_x + delta, GetMaxDragX(active_index())) :
diff --git a/chrome/browser/ui/views/tabs/stacked_tab_strip_layout_unittest.cc b/chrome/browser/ui/views/tabs/stacked_tab_strip_layout_unittest.cc
index 8c9a88f..073d4d6 100644
--- a/chrome/browser/ui/views/tabs/stacked_tab_strip_layout_unittest.cc
+++ b/chrome/browser/ui/views/tabs/stacked_tab_strip_layout_unittest.cc
@@ -257,6 +257,28 @@
     // Drags one past as far to the left as the tab goes. Should keep pulling
     // in the rightmost tab.
     { { 0, 240, 100, 10, 2, 0, 1, "0 90 140", "0 2 91" }, -89 },
+
+    //
+    // The following set of tests create six tabs with the third selected.
+    //
+    // The x-position of the third tab is at its maximum, and the second tab is
+    // stacked underneath. Dragging to the left moves the second tab to the
+    // stack at the left-hand side of the tab strip.
+    { { 0, 150, 100, 10, 2, 0, 2, "0 42 44 46 48 50", "0 2 43 46 48 50" }, -1 },
+    { { 0, 150, 100, 10, 2, 0, 2, "0 20 44 46 48 50", "0 2 41 46 48 50" }, -3 },
+    // The x-position of the third tab is not at its maximum. Dragging to the
+    // left moves the second and third tabs by the same delta.
+    { { 0, 150, 100, 10, 2, 0, 2, "0 25 35 46 48 50", "0 20 30 46 48 50" },
+      -5 },
+    // min x, fourth is flush against right side
+    // The x-position of the third tab is at its minimum, and the fourth tab is
+    // stacked underneath. Dragging to the right moves the fourth and fifth tabs
+    // to the stack at the right-hand side of the tab strip.
+    { { 0, 150, 100, 10, 2, 0, 2, "0 2 4 6 25 50", "0 2 11 46 48 50" }, 7 },
+    { { 0, 150, 100, 10, 2, 0, 2, "0 2 4 9 25 50", "0 2 7 46 48 50" }, 3 },
+    // The x-position of the third tab is not at its minimum. Dragging to the
+    // right moves the third, fourth, and fifth tabs by the same delta.
+    { { 0, 150, 100, 10, 2, 0, 2, "0 2 10 16 25 50", "0 2 11 17 26 50" }, 1 },
   };
 
   for (size_t i = 0; i < arraysize(test_data); ++i) {
diff --git a/chrome/browser/ui/views/toolbar/app_menu_button.cc b/chrome/browser/ui/views/toolbar/app_menu_button.cc
index e51aa27..b36e966 100644
--- a/chrome/browser/ui/views/toolbar/app_menu_button.cc
+++ b/chrome/browser/ui/views/toolbar/app_menu_button.cc
@@ -14,11 +14,12 @@
 #include "cc/paint/paint_flags.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/themes/theme_properties.h"
+#include "chrome/browser/themes/theme_service.h"
+#include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_otr_state.h"
 #include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/browser/ui/toolbar/app_menu_animation.h"
 #include "chrome/browser/ui/toolbar/app_menu_model.h"
 #include "chrome/browser/ui/views/extensions/browser_action_drag_data.h"
 #include "chrome/browser/ui/views/toolbar/app_menu.h"
@@ -46,12 +47,7 @@
 
 AppMenuButton::AppMenuButton(ToolbarView* toolbar_view)
     : views::MenuButton(base::string16(), toolbar_view, false),
-      severity_(AppMenuIconController::Severity::NONE),
-      type_(AppMenuIconController::IconType::NONE),
-      toolbar_view_(toolbar_view),
-      should_use_new_icon_(false),
-      margin_trailing_(0),
-      weak_factory_(this) {
+      toolbar_view_(toolbar_view) {
   SetInkDropMode(InkDropMode::ON);
   SetFocusPainter(nullptr);
 
@@ -133,7 +129,8 @@
 }
 
 void AppMenuButton::Layout() {
-  if (animation_) {
+  if (new_icon_) {
+    new_icon_->SetBoundsRect(GetContentsBounds());
     ink_drop_container()->SetBoundsRect(GetLocalBounds());
     image()->SetBoundsRect(GetLocalBounds());
     return;
@@ -142,15 +139,8 @@
   views::MenuButton::Layout();
 }
 
-void AppMenuButton::PaintButtonContents(gfx::Canvas* canvas) {
-  if (!animation_) {
-    views::MenuButton::PaintButtonContents(canvas);
-    return;
-  }
-
-  gfx::Rect bounds = GetLocalBounds();
-  bounds.Inset(gfx::Insets(ToolbarButton::kInteriorPadding));
-  animation_->PaintAppMenu(canvas, bounds);
+void AppMenuButton::OnThemeChanged() {
+  UpdateIcon(false);
 }
 
 void AppMenuButton::TabInsertedAt(TabStripModel* tab_strip_model,
@@ -160,19 +150,6 @@
   AnimateIconIfPossible();
 }
 
-void AppMenuButton::AppMenuAnimationStarted() {
-  SetPaintToLayer();
-  layer()->SetFillsBoundsOpaquely(false);
-}
-
-void AppMenuButton::AppMenuAnimationEnded() {
-  DestroyLayer();
-}
-
-void AppMenuButton::InvalidateIcon() {
-  SchedulePaint();
-}
-
 void AppMenuButton::UpdateIcon(bool should_animate) {
   SkColor severity_color = gfx::kPlaceholderColor;
   SkColor toolbar_icon_color =
@@ -197,10 +174,21 @@
   }
 
   if (should_use_new_icon_) {
-    if (!animation_)
-      animation_ = base::MakeUnique<AppMenuAnimation>(this, toolbar_icon_color);
+    if (!new_icon_) {
+      new_icon_ = new views::AnimatedIconView(kBrowserToolsAnimatedIcon);
+      new_icon_->set_can_process_events_within_subtree(false);
+      AddChildView(new_icon_);
+    }
 
-    animation_->set_target_color(severity_color);
+    // Only show a special color for severity when using the classic Chrome
+    // theme. Otherwise, we can't be sure that it contrasts with the toolbar
+    // background.
+    new_icon_->set_color(
+        ThemeServiceFactory::GetForProfile(toolbar_view_->browser()->profile())
+                ->UsingDefaultTheme()
+            ? severity_color
+            : toolbar_icon_color);
+
     if (should_animate)
       AnimateIconIfPossible();
 
@@ -233,12 +221,12 @@
 }
 
 void AppMenuButton::AnimateIconIfPossible() {
-  if (!animation_ || !should_use_new_icon_ ||
+  if (!new_icon_ || !should_use_new_icon_ ||
       severity_ == AppMenuIconController::Severity::NONE) {
     return;
   }
 
-  animation_->StartAnimation();
+  new_icon_->Animate(views::AnimatedIconView::END);
 }
 
 const char* AppMenuButton::GetClassName() const {
diff --git a/chrome/browser/ui/views/toolbar/app_menu_button.h b/chrome/browser/ui/views/toolbar/app_menu_button.h
index 804c5f6..c06fb0d 100644
--- a/chrome/browser/ui/views/toolbar/app_menu_button.h
+++ b/chrome/browser/ui/views/toolbar/app_menu_button.h
@@ -10,8 +10,8 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
-#include "chrome/browser/ui/toolbar/app_menu_animation.h"
 #include "chrome/browser/ui/toolbar/app_menu_icon_controller.h"
+#include "ui/views/controls/animated_icon_view.h"
 #include "ui/views/controls/button/menu_button.h"
 #include "ui/views/controls/button/menu_button_listener.h"
 #include "ui/views/view.h"
@@ -26,9 +26,10 @@
 
 class ToolbarView;
 
-class AppMenuButton : public views::MenuButton,
-                      public TabStripModelObserver,
-                      public AppMenuAnimationDelegate {
+// The app menu button lives in the top right of the main browser window. It
+// shows three dots and animates to a hamburger-ish icon when there's a need to
+// alert the user. Clicking displays the app menu.
+class AppMenuButton : public views::MenuButton, public TabStripModelObserver {
  public:
   explicit AppMenuButton(ToolbarView* toolbar_view);
   ~AppMenuButton() override;
@@ -58,7 +59,7 @@
   // views::MenuButton:
   gfx::Size CalculatePreferredSize() const override;
   void Layout() override;
-  void PaintButtonContents(gfx::Canvas* canvas) override;
+  void OnThemeChanged() override;
 
   // TabStripObserver:
   void TabInsertedAt(TabStripModel* tab_strip_model,
@@ -66,11 +67,6 @@
                      int index,
                      bool foreground) override;
 
-  // AppMenuAnimationDelegate:
-  void AppMenuAnimationStarted() override;
-  void AppMenuAnimationEnded() override;
-  void InvalidateIcon() override;
-
   // Updates the presentation according to |severity_| and the theme provider.
   // If |should_animate| is true, the icon should animate.
   void UpdateIcon(bool should_animate);
@@ -103,8 +99,9 @@
   void OnDragExited() override;
   int OnPerformDrop(const ui::DropTargetEvent& event) override;
 
-  AppMenuIconController::Severity severity_;
-  AppMenuIconController::IconType type_;
+  AppMenuIconController::Severity severity_ =
+      AppMenuIconController::Severity::NONE;
+  AppMenuIconController::IconType type_ = AppMenuIconController::IconType::NONE;
 
   // Our owning toolbar view.
   ToolbarView* toolbar_view_;
@@ -118,18 +115,20 @@
   std::unique_ptr<AppMenuModel> menu_model_;
   std::unique_ptr<AppMenu> menu_;
 
-  // Used for animating and drawing the app menu icon.
-  std::unique_ptr<AppMenuAnimation> animation_;
+  // The view that depicts and animates the icon. TODO(estade): rename to
+  // |animated_icon_| when |should_use_new_icon_| defaults to true and is
+  // removed.
+  views::AnimatedIconView* new_icon_ = nullptr;
 
   // True if the app menu should use the new animated icon.
-  bool should_use_new_icon_;
+  bool should_use_new_icon_ = false;
 
   // Any trailing margin to be applied. Used when the browser is in
   // a maximized state to extend to the full window width.
-  int margin_trailing_;
+  int margin_trailing_ = 0;
 
   // Used to spawn weak pointers for delayed tasks to open the overflow menu.
-  base::WeakPtrFactory<AppMenuButton> weak_factory_;
+  base::WeakPtrFactory<AppMenuButton> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(AppMenuButton);
 };
diff --git a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h
index c263fa2..d8a0dee8 100644
--- a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h
@@ -15,8 +15,8 @@
 #include "chrome/browser/chromeos/policy/enrollment_config.h"
 #include "chrome/browser/ui/webui/chromeos/login/base_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/network_state_informer.h"
+#include "chromeos/dbus/auth_policy_client.h"
 #include "net/base/net_errors.h"
-#include "third_party/cros_system_api/dbus/service_constants.h"
 
 namespace chromeos {
 
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h
index 15a6b10..79f9fba2 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h
@@ -14,9 +14,9 @@
 #include "chrome/browser/chromeos/login/screens/gaia_view.h"
 #include "chrome/browser/ui/webui/chromeos/login/base_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/network_state_informer.h"
+#include "chromeos/dbus/auth_policy_client.h"
 #include "chromeos/network/portal_detector/network_portal_detector.h"
 #include "net/base/net_errors.h"
-#include "third_party/cros_system_api/dbus/service_constants.h"
 
 class AccountId;
 
diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
index 33bdf4c..ef02641 100644
--- a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
@@ -175,6 +175,10 @@
                             IDR_CUSTOM_ELEMENTS_LOGIN_HTML);
     source->AddResourcePath(kCustomElementsJSPath,
                             IDR_CUSTOM_ELEMENTS_LOGIN_JS);
+    source->AddResourcePath(kCustomElementsPinKeyboardHTMLPath,
+                            IDR_CUSTOM_ELEMENTS_PIN_KEYBOARD_HTML);
+    source->AddResourcePath(kCustomElementsPinKeyboardJSPath,
+                            IDR_CUSTOM_ELEMENTS_PIN_KEYBOARD_JS);
     source->AddResourcePath(kCustomElementsUserPodHTMLPath,
                             IDR_CUSTOM_ELEMENTS_USER_POD_HTML);
   }
diff --git a/chrome/browser/ui/webui/settings/md_settings_ui.cc b/chrome/browser/ui/webui/settings/md_settings_ui.cc
index d073d8df..270df59 100644
--- a/chrome/browser/ui/webui/settings/md_settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_ui.cc
@@ -83,6 +83,12 @@
 
 namespace settings {
 
+bool IsValidOrigin(const GURL& url) {
+  const GURL origin = url.GetOrigin();
+  return origin == GURL(chrome::kChromeUISettingsURL).GetOrigin() ||
+         origin == GURL(chrome::kChromeUIMdSettingsURL).GetOrigin();
+}
+
 // static
 void MdSettingsUI::RegisterProfilePrefs(
     user_prefs::PrefRegistrySyncable* registry) {
@@ -161,8 +167,7 @@
 
   // Host must be derived from the visible URL, since this might be serving
   // either chrome://settings or chrome://md-settings.
-  CHECK(url.GetOrigin() == GURL(chrome::kChromeUISettingsURL).GetOrigin() ||
-        url.GetOrigin() == GURL(chrome::kChromeUIMdSettingsURL).GetOrigin());
+  CHECK(IsValidOrigin(url));
 
   content::WebUIDataSource* html_source =
       content::WebUIDataSource::Create(url.host());
diff --git a/chrome/browser/ui/webui/settings/md_settings_ui.h b/chrome/browser/ui/webui/settings/md_settings_ui.h
index 2262702..7aef511 100644
--- a/chrome/browser/ui/webui/settings/md_settings_ui.h
+++ b/chrome/browser/ui/webui/settings/md_settings_ui.h
@@ -22,6 +22,9 @@
 
 class SettingsPageUIHandler;
 
+// Exposed for testing.
+bool IsValidOrigin(const GURL& url);
+
 // The WebUI handler for chrome://md-settings.
 class MdSettingsUI : public content::WebUIController,
                      public content::WebContentsObserver {
diff --git a/chrome/browser/ui/webui/settings/md_settings_ui_browsertest.cc b/chrome/browser/ui/webui/settings/md_settings_ui_browsertest.cc
index 056310a2..6d48ade 100644
--- a/chrome/browser/ui/webui/settings/md_settings_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_ui_browsertest.cc
@@ -5,7 +5,6 @@
 #include <string>
 
 #include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/test/base/in_process_browser_test.h"
@@ -14,14 +13,11 @@
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_message_handler.h"
 #include "content/public/common/url_constants.h"
-#include "content/public/test/browser_test_utils.h"
-#include "ui/base/window_open_disposition.h"
 #include "url/gurl.h"
 
 typedef InProcessBrowserTest MdSettingsUITest;
 
 using ui_test_utils::NavigateToURL;
-using content::WaitForLoadStop;
 
 IN_PROC_BROWSER_TEST_F(MdSettingsUITest, ViewSourceDoesntCrash) {
   NavigateToURL(browser(), GURL(content::kViewSourceScheme + std::string(":") +
@@ -29,27 +25,6 @@
                                 std::string("strings.js")));
 }
 
-// May not complete on memory and Windows debug bots. TODO(dbeam): investigate
-// and fix. See https://crbug.com/558434, https://crbug.com/620370 and
-// https://crbug.com/651296.
-//
-// Disabled for ASan. See http://crbug.com/727449.
-#if defined(MEMORY_SANITIZER) || defined(OS_WIN) || defined(OS_CHROMEOS) || \
-    defined(ADDRESS_SANITIZER)
-#define MAYBE_BackForwardDoesntCrash DISABLED_BackForwardDoesntCrash
-#else
-#define MAYBE_BackForwardDoesntCrash BackForwardDoesntCrash
-#endif
-
-IN_PROC_BROWSER_TEST_F(MdSettingsUITest, MAYBE_BackForwardDoesntCrash) {
-  NavigateToURL(browser(), GURL(chrome::kChromeUIMdSettingsURL));
-
-  NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL));
-
-  chrome::GoBack(browser(), WindowOpenDisposition::CURRENT_TAB);
-  WaitForLoadStop(browser()->tab_strip_model()->GetActiveWebContents());
-}
-
 // Catch lifetime issues in message handlers. There was previously a problem
 // with PrefMember calling Init again after Destroy.
 IN_PROC_BROWSER_TEST_F(MdSettingsUITest, ToggleJavaScript) {
diff --git a/chrome/browser/ui/webui/settings/md_settings_ui_unittest.cc b/chrome/browser/ui/webui/settings/md_settings_ui_unittest.cc
new file mode 100644
index 0000000..01b5041
--- /dev/null
+++ b/chrome/browser/ui/webui/settings/md_settings_ui_unittest.cc
@@ -0,0 +1,20 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/settings/md_settings_ui.h"
+
+#include "chrome/common/url_constants.h"
+#include "content/public/common/url_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+TEST(MdSettingsUITest, IsValidOrigin) {
+  EXPECT_TRUE(settings::IsValidOrigin(GURL(chrome::kChromeUISettingsURL)));
+  EXPECT_TRUE(settings::IsValidOrigin(GURL(chrome::kChromeUIMdSettingsURL)));
+
+  EXPECT_FALSE(settings::IsValidOrigin(GURL("http://evil.com")));
+  EXPECT_FALSE(settings::IsValidOrigin(GURL("https://google.com")));
+  EXPECT_FALSE(settings::IsValidOrigin(GURL(chrome::kChromeUINewTabURL)));
+  EXPECT_FALSE(settings::IsValidOrigin(GURL(chrome::kChromeUIHistoryURL)));
+}
diff --git a/chrome/browser/ui/webui/sync_internals_message_handler.cc b/chrome/browser/ui/webui/sync_internals_message_handler.cc
index e67fbc1..c629de94 100644
--- a/chrome/browser/ui/webui/sync_internals_message_handler.cc
+++ b/chrome/browser/ui/webui/sync_internals_message_handler.cc
@@ -215,8 +215,7 @@
 
   Profile* profile = Profile::FromWebUI(web_ui());
   syncer::UserEventService* user_event_service =
-      browser_sync::UserEventServiceFactory::GetForProfile(
-          profile->GetOriginalProfile());
+      browser_sync::UserEventServiceFactory::GetForProfile(profile);
 
   sync_pb::UserEventSpecifics event_specifics;
   event_specifics.set_event_time_usec(StringAtIndexToInt64(args, 0));
diff --git a/chrome/browser/ui/webui/sync_internals_message_handler_unittest.cc b/chrome/browser/ui/webui/sync_internals_message_handler_unittest.cc
index 41299ef..c026478 100644
--- a/chrome/browser/ui/webui/sync_internals_message_handler_unittest.cc
+++ b/chrome/browser/ui/webui/sync_internals_message_handler_unittest.cc
@@ -17,6 +17,7 @@
 #include "components/sync/driver/fake_sync_service.h"
 #include "components/sync/driver/sync_service.h"
 #include "components/sync/js/js_test_util.h"
+#include "components/sync/user_events/fake_user_event_service.h"
 #include "content/public/browser/site_instance.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/test_browser_thread_bundle.h"
@@ -26,6 +27,7 @@
 using base::DictionaryValue;
 using base::ListValue;
 using base::Value;
+using syncer::FakeUserEventService;
 using syncer::SyncService;
 using syncer::SyncServiceObserver;
 using syncer::TypeDebugInfoObserver;
@@ -97,6 +99,11 @@
   return base::MakeUnique<TestSyncService>();
 }
 
+static std::unique_ptr<KeyedService> BuildFakeUserEventService(
+    content::BrowserContext* context) {
+  return base::MakeUnique<FakeUserEventService>();
+}
+
 class SyncInternalsMessageHandlerTest : public ::testing::Test {
  protected:
   SyncInternalsMessageHandlerTest() {
@@ -107,6 +114,9 @@
     test_sync_service_ = static_cast<TestSyncService*>(
         ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse(
             &profile_, &BuildTestSyncService));
+    fake_user_event_service_ = static_cast<FakeUserEventService*>(
+        browser_sync::UserEventServiceFactory::GetInstance()
+            ->SetTestingFactoryAndUse(&profile_, &BuildFakeUserEventService));
     handler_.reset(new TestableSyncInternalsMessageHandler(
         &web_ui_,
         base::BindRepeating(
@@ -158,6 +168,10 @@
 
   TestSyncService* test_sync_service() { return test_sync_service_; }
 
+  FakeUserEventService* fake_user_event_service() {
+    return fake_user_event_service_;
+  }
+
   TestableSyncInternalsMessageHandler* handler() { return handler_.get(); }
 
   int CallCountWithName(const std::string& function_name) {
@@ -187,6 +201,7 @@
   std::unique_ptr<content::WebContents> web_contents_;
   content::TestWebUI web_ui_;
   TestSyncService* test_sync_service_;
+  FakeUserEventService* fake_user_event_service_;
   std::unique_ptr<TestableSyncInternalsMessageHandler> handler_;
   int about_sync_data_delegate_call_count_ = 0;
   SyncService* last_delegate_sync_service_ = nullptr;
@@ -315,4 +330,30 @@
   ValidateAboutInfoCall();
 }
 
+TEST_F(SyncInternalsMessageHandlerTest, WriteUserEvent) {
+  ListValue args;
+  args.AppendString("1000000000000000000");
+  args.AppendString("-1");
+  handler()->HandleWriteUserEvent(&args);
+
+  ASSERT_EQ(1u, fake_user_event_service()->GetRecordedUserEvents().size());
+  const sync_pb::UserEventSpecifics& event =
+      *fake_user_event_service()->GetRecordedUserEvents().begin();
+  EXPECT_EQ(1000000000000000000, event.event_time_usec());
+  EXPECT_EQ(-1, event.navigation_id());
+}
+
+TEST_F(SyncInternalsMessageHandlerTest, WriteUserEventBadParse) {
+  ListValue args;
+  args.AppendString("123abc");
+  args.AppendString("");
+  handler()->HandleWriteUserEvent(&args);
+
+  ASSERT_EQ(1u, fake_user_event_service()->GetRecordedUserEvents().size());
+  const sync_pb::UserEventSpecifics& event =
+      *fake_user_event_service()->GetRecordedUserEvents().begin();
+  EXPECT_EQ(0, event.event_time_usec());
+  EXPECT_EQ(0, event.navigation_id());
+}
+
 }  // namespace
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn
index eafd8cd..66c7dc8 100644
--- a/chrome/common/BUILD.gn
+++ b/chrome/common/BUILD.gn
@@ -706,6 +706,17 @@
   ]
 }
 
+mojom("once_callback_mojo_bindings") {
+  sources = [
+    "safe_browsing.mojom",
+  ]
+
+  public_deps = [
+    "//content/public/common:resource_type_bindings",
+    "//url/mojo:url_mojom_gurl",
+  ]
+}
+
 mojom("mojo_bindings") {
   sources = [
     "cache_stats_recorder.mojom",
@@ -732,6 +743,7 @@
   }
 
   public_deps = [
+    ":once_callback_mojo_bindings",
     "//components/content_settings/core/common:mojo_bindings",
     "//mojo/common:common_custom_types",
     "//ui/gfx/geometry/mojo",
diff --git a/chrome/common/extensions/api/automation.idl b/chrome/common/extensions/api/automation.idl
index 4c6e957..c01f356 100644
--- a/chrome/common/extensions/api/automation.idl
+++ b/chrome/common/extensions/api/automation.idl
@@ -216,7 +216,6 @@
     multiline,
     multiselectable,
     offscreen,
-    pressed,
     protected,
     readOnly,
     required,
diff --git a/chrome/common/logging_chrome.cc b/chrome/common/logging_chrome.cc
index 4e2df8c..8f67671 100644
--- a/chrome/common/logging_chrome.cc
+++ b/chrome/common/logging_chrome.cc
@@ -47,7 +47,6 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/threading/thread_restrictions.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
@@ -66,11 +65,12 @@
 #include "chrome/install_static/install_details.h"
 #endif
 
+namespace logging {
 namespace {
 
 // When true, this means that error dialogs should not be shown.
 bool dialogs_are_suppressed_ = false;
-logging::ScopedLogAssertHandler* assert_handler_ = nullptr;
+ScopedLogAssertHandler* assert_handler_ = nullptr;
 
 // This should be true for exactly the period between the end of
 // InitChromeLogging() and the beginning of CleanupChromeLogging().
@@ -108,8 +108,8 @@
   if (dialogs_are_suppressed_)
     return;
 
-  assert_handler_ = new logging::ScopedLogAssertHandler(
-      base::Bind(SilentRuntimeAssertHandler));
+  assert_handler_ =
+      new ScopedLogAssertHandler(base::Bind(SilentRuntimeAssertHandler));
 
 #if defined(OS_WIN)
   UINT new_flags = SEM_FAILCRITICALERRORS |
@@ -126,39 +126,37 @@
 
 }  // anonymous namespace
 
-namespace logging {
-
-LoggingDestination DetermineLogMode(const base::CommandLine& command_line) {
-  // only use OutputDebugString in debug mode
+LoggingDestination DetermineLoggingDestination(
+    const base::CommandLine& command_line) {
+// only use OutputDebugString in debug mode
 #ifdef NDEBUG
   bool enable_logging = false;
   const char *kInvertLoggingSwitch = switches::kEnableLogging;
-  const logging::LoggingDestination kDefaultLoggingMode = logging::LOG_TO_FILE;
+  const LoggingDestination kDefaultLoggingMode = LOG_TO_FILE;
 #else
   bool enable_logging = true;
   const char *kInvertLoggingSwitch = switches::kDisableLogging;
-  const logging::LoggingDestination kDefaultLoggingMode = logging::LOG_TO_ALL;
+  const LoggingDestination kDefaultLoggingMode = LOG_TO_ALL;
 #endif
 
   if (command_line.HasSwitch(kInvertLoggingSwitch))
     enable_logging = !enable_logging;
 
-  logging::LoggingDestination log_mode;
+  LoggingDestination log_mode;
   if (enable_logging) {
     // Let --enable-logging=stderr force only stderr, particularly useful for
     // non-debug builds where otherwise you can't get logs to stderr at all.
     if (command_line.GetSwitchValueASCII(switches::kEnableLogging) == "stderr")
-      log_mode = logging::LOG_TO_SYSTEM_DEBUG_LOG;
+      log_mode = LOG_TO_SYSTEM_DEBUG_LOG;
     else
       log_mode = kDefaultLoggingMode;
   } else {
-    log_mode = logging::LOG_NONE;
+    log_mode = LOG_NONE;
   }
   return log_mode;
 }
 
 #if defined(OS_CHROMEOS)
-namespace {
 base::FilePath SetUpSymlinkIfNeeded(const base::FilePath& symlink_path,
                                     bool new_log) {
   DCHECK(!symlink_path.empty());
@@ -196,8 +194,6 @@
     DPLOG(WARNING) << "Unable to unlink log file " << target_path.value();
 }
 
-}  // anonymous namespace
-
 base::FilePath GetSessionLogDir(const base::CommandLine& command_line) {
   base::FilePath log_dir;
   std::string log_dir_str;
@@ -228,39 +224,6 @@
   return GetSessionLogDir(command_line).Append(GetLogFileName().BaseName());
 }
 
-void RedirectChromeLogging(const base::CommandLine& command_line) {
-  if (chrome_logging_redirected_) {
-    // TODO(nkostylev): Support multiple active users. http://crbug.com/230345
-    LOG(WARNING) << "NOT redirecting logging for multi-profiles case.";
-    return;
-  }
-
-  DCHECK(!chrome_logging_redirected_) <<
-    "Attempted to redirect logging when it was already initialized.";
-
-  // Redirect logs to the session log directory, if set.  Otherwise
-  // defaults to the profile dir.
-  base::FilePath log_path = GetSessionLogFile(command_line);
-
-  // Creating symlink causes us to do blocking IO on UI thread.
-  // Temporarily allow it until we fix http://crbug.com/61143
-  base::ThreadRestrictions::ScopedAllowIO allow_io;
-  // Always force a new symlink when redirecting.
-  base::FilePath target_path = SetUpSymlinkIfNeeded(log_path, true);
-
-  // ChromeOS always logs through the symlink, so it shouldn't be
-  // deleted if it already exists.
-  logging::LoggingSettings settings;
-  settings.logging_dest = DetermineLogMode(command_line);
-  settings.log_file = log_path.value().c_str();
-  if (!logging::InitLogging(settings)) {
-    DLOG(ERROR) << "Unable to initialize logging to " << log_path.value();
-    RemoveSymlinkAndLog(log_path, target_path);
-  } else {
-    chrome_logging_redirected_ = true;
-  }
-}
-
 #endif  // OS_CHROMEOS
 
 void InitChromeLogging(const base::CommandLine& command_line,
@@ -268,7 +231,7 @@
   DCHECK(!chrome_logging_initialized_) <<
     "Attempted to initialize logging when it was already initialized.";
 
-  LoggingDestination logging_dest = DetermineLogMode(command_line);
+  LoggingDestination logging_dest = DetermineLoggingDestination(command_line);
   LogLockingState log_locking_state = LOCK_LOG_FILE;
   base::FilePath log_path;
 #if defined(OS_CHROMEOS)
@@ -291,23 +254,23 @@
     // symlink if we've been asked to delete the old log, since that
     // indicates the start of a new session.
     target_path = SetUpSymlinkIfNeeded(
-        log_path, delete_old_log_file == logging::DELETE_OLD_LOG_FILE);
+        log_path, delete_old_log_file == DELETE_OLD_LOG_FILE);
 
     // Because ChromeOS manages the move to a new session by redirecting
     // the link, it shouldn't remove the old file in the logging code,
     // since that will remove the newly created link instead.
-    delete_old_log_file = logging::APPEND_TO_OLD_LOG_FILE;
+    delete_old_log_file = APPEND_TO_OLD_LOG_FILE;
 #endif
   } else {
     log_locking_state = DONT_LOCK_LOG_FILE;
   }
 
-  logging::LoggingSettings settings;
+  LoggingSettings settings;
   settings.logging_dest = logging_dest;
   settings.log_file = log_path.value().c_str();
   settings.lock_log = log_locking_state;
   settings.delete_old = delete_old_log_file;
-  bool success = logging::InitLogging(settings);
+  bool success = InitLogging(settings);
 
 #if defined(OS_CHROMEOS)
   if (!success) {
@@ -328,13 +291,13 @@
   // Default to showing error dialogs.
   if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kNoErrorDialogs))
-    logging::SetShowErrorDialogs(true);
+    SetShowErrorDialogs(true);
 
   // we want process and thread IDs because we have a lot of things running
-  logging::SetLogItems(true,  // enable_process_id
-                       true,  // enable_thread_id
-                       true,  // enable_timestamp
-                       false);  // enable_tickcount
+  SetLogItems(true,    // enable_process_id
+              true,    // enable_thread_id
+              true,    // enable_timestamp
+              false);  // enable_tickcount
 
   // We call running in unattended mode "headless", and allow
   // headless mode to be configured either by the Environment
@@ -348,17 +311,17 @@
   // Use a minimum log level if the command line asks for one. Ignore this
   // switch if there's vlog level switch present too (as both of these switches
   // refer to the same underlying log level, and the vlog level switch has
-  // already been processed inside logging::InitLogging). If there is neither
+  // already been processed inside InitLogging). If there is neither
   // log level nor vlog level specified, then just leave the default level
   // (INFO).
   if (command_line.HasSwitch(switches::kLoggingLevel) &&
-      logging::GetMinLogLevel() >= 0) {
+      GetMinLogLevel() >= 0) {
     std::string log_level =
         command_line.GetSwitchValueASCII(switches::kLoggingLevel);
     int level = 0;
     if (base::StringToInt(log_level, &level) && level >= 0 &&
         level < LOG_NUM_SEVERITIES) {
-      logging::SetMinLogLevel(level);
+      SetMinLogLevel(level);
     } else {
       DLOG(WARNING) << "Bad log level: " << log_level;
     }
@@ -366,10 +329,10 @@
 
 #if defined(OS_WIN)
   // Enable trace control and transport through event tracing for Windows.
-  logging::LogEventProvider::Initialize(kChromeTraceProviderName);
+  LogEventProvider::Initialize(kChromeTraceProviderName);
 
   // Enable logging to the Windows Event Log.
-  logging::SetEventSourceName(base::UTF16ToASCII(
+  SetEventSourceName(base::UTF16ToASCII(
       install_static::InstallDetails::Get().install_full_name()));
 #endif
 
diff --git a/chrome/common/logging_chrome.h b/chrome/common/logging_chrome.h
index 58acda6..42ba0343 100644
--- a/chrome/common/logging_chrome.h
+++ b/chrome/common/logging_chrome.h
@@ -32,15 +32,23 @@
 void InitChromeLogging(const base::CommandLine& command_line,
                        OldFileDeletionState delete_old_log_file);
 
+LoggingDestination DetermineLoggingDestination(
+    const base::CommandLine& command_line);
+
 #if defined(OS_CHROMEOS)
+// Point the logging symlink to the system log or the user session log.
+base::FilePath SetUpSymlinkIfNeeded(const base::FilePath& symlink_path,
+                                    bool new_log);
+
+// Remove the logging symlink.
+void RemoveSymlinkAndLog(const base::FilePath& link_path,
+                         const base::FilePath& target_path);
+
 // Get the log file directory path.
 base::FilePath GetSessionLogDir(const base::CommandLine& command_line);
 
 // Get the log file location.
 base::FilePath GetSessionLogFile(const base::CommandLine& command_line);
-
-// Redirects chrome logging to the appropriate session log dir.
-void RedirectChromeLogging(const base::CommandLine& command_line);
 #endif
 
 // Call when done using logging for Chrome.
diff --git a/chrome/common/safe_browsing.mojom b/chrome/common/safe_browsing.mojom
new file mode 100644
index 0000000..07253a33
--- /dev/null
+++ b/chrome/common/safe_browsing.mojom
@@ -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.
+
+module chrome.mojom;
+
+import "content/public/common/resource_type.mojom";
+import "url/mojo/url.mojom";
+
+interface SafeBrowsing {
+  // Queries SafeBrowsing whether |url| is safe to load, and creates a
+  // SafeBrowsingUrlChecker interface.
+  // This checker interface should be used (and only used) for subsequent checks
+  // of redirects, so that the server side could keep track of the redirect
+  // chain. Disconnecting the checker interface cancels on-going URL checks.
+  // Please note that in that case if the check started by this method hasn't
+  // completed yet, it will also be canceled and return true as if the URL is
+  // safe.
+  // The check and (subsequent checks performed using SafeBrowsingUrlChecker)
+  // checks against SafeBrowsing's Malware, Phishing, and UwS blacklists.
+  CreateCheckerAndCheck(
+      int32 render_frame_id,
+      SafeBrowsingUrlChecker& request,
+      url.mojom.Url url,
+      int32 load_flags,
+      content.mojom.ResourceType resource_type) => (bool safe);
+};
+
+interface SafeBrowsingUrlChecker {
+  CheckUrl(url.mojom.Url url) => (bool safe);
+};
diff --git a/chrome/installer/mac/BUILD.gn b/chrome/installer/mac/BUILD.gn
index d6ad7cf1..616dee3 100644
--- a/chrome/installer/mac/BUILD.gn
+++ b/chrome/installer/mac/BUILD.gn
@@ -26,6 +26,10 @@
   script = "//build/gn_run_binary.py"
   shell_script = "//chrome/installer/mac/make_signers.sh"
 
+  deps = [
+    ":copy_variables",
+  ]
+
   inputs = [
     script,
     shell_script,
@@ -49,10 +53,24 @@
   ]
 }
 
+copy("copy_variables") {
+  visibility = [
+    ":make_signers",
+    ":copies",
+  ]
+  sources = [
+    "variables.sh",
+  ]
+  outputs = [
+    "$_packaging_dir/{{source_file_part}}",
+  ]
+}
+
 copy("copies") {
   visibility = [ ":mac" ]
 
   deps = [
+    ":copy_variables",
     "//chrome/installer/mac/third_party/bsdiff:goobsdiff",
     "//chrome/installer/mac/third_party/bsdiff:goobspatch",
     "//chrome/installer/mac/third_party/xz:lzma_decompress",
@@ -71,7 +89,6 @@
     "dmgdiffer.sh",
     "pkg-dmg",
     "sign_installer_tools.sh",
-    "variables.sh",
   ]
 
   if (is_chrome_branded) {
diff --git a/chrome/renderer/BUILD.gn b/chrome/renderer/BUILD.gn
index 6a491d4..c7944f4 100644
--- a/chrome/renderer/BUILD.gn
+++ b/chrome/renderer/BUILD.gn
@@ -84,6 +84,8 @@
     "prerender/prerender_helper.h",
     "prerender/prerenderer_client.cc",
     "prerender/prerenderer_client.h",
+    "safe_browsing/safe_browsing_url_loader_throttle.cc",
+    "safe_browsing/safe_browsing_url_loader_throttle.h",
     "sandbox_status_extension_android.cc",
     "sandbox_status_extension_android.h",
     "searchbox/search_bouncer.cc",
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc
index 1ef52dd4..95f3aa6 100644
--- a/chrome/renderer/chrome_content_renderer_client.cc
+++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -57,6 +57,7 @@
 #include "chrome/renderer/prerender/prerender_helper.h"
 #include "chrome/renderer/prerender/prerenderer_client.h"
 #include "chrome/renderer/safe_browsing/phishing_classifier_delegate.h"
+#include "chrome/renderer/safe_browsing/safe_browsing_url_loader_throttle.h"
 #include "chrome/renderer/searchbox/search_bouncer.h"
 #include "chrome/renderer/searchbox/searchbox.h"
 #include "chrome/renderer/searchbox/searchbox_extension.h"
@@ -106,6 +107,7 @@
 #include "ppapi/shared_impl/ppapi_switches.h"
 #include "printing/features/features.h"
 #include "services/service_manager/public/cpp/connector.h"
+#include "services/service_manager/public/cpp/interface_provider.h"
 #include "third_party/WebKit/public/platform/URLConversion.h"
 #include "third_party/WebKit/public/platform/WebCache.h"
 #include "third_party/WebKit/public/platform/WebCachePolicy.h"
@@ -1197,7 +1199,20 @@
     WebLocalFrame* frame,
     ui::PageTransition transition_type,
     const blink::WebURL& url,
+    std::vector<std::unique_ptr<content::URLLoaderThrottle>>* throttles,
     GURL* new_url) {
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableNetworkService)) {
+    if (!safe_browsing_) {
+      RenderThread::Get()->GetConnector()->BindInterface(
+          content::mojom::kBrowserServiceName, &safe_browsing_);
+    }
+    RenderFrame* render_frame = content::RenderFrame::FromWebFrame(frame);
+    throttles->push_back(
+        base::MakeUnique<safe_browsing::SafeBrowsingURLLoaderThrottle>(
+            safe_browsing_.get(), render_frame->GetRoutingID()));
+  }
+
 // Check whether the request should be allowed. If not allowed, we reset the
 // URL to something invalid to prevent the request and cause an error.
 #if BUILDFLAG(ENABLE_EXTENSIONS)
diff --git a/chrome/renderer/chrome_content_renderer_client.h b/chrome/renderer/chrome_content_renderer_client.h
index dd11c11a..6129a48 100644
--- a/chrome/renderer/chrome_content_renderer_client.h
+++ b/chrome/renderer/chrome_content_renderer_client.h
@@ -16,6 +16,7 @@
 #include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/strings/string16.h"
+#include "chrome/common/safe_browsing.mojom.h"
 #include "chrome/renderer/media/chrome_key_systems_provider.h"
 #include "components/rappor/public/interfaces/rappor_recorder.mojom.h"
 #include "components/spellcheck/spellcheck_build_features.h"
@@ -136,10 +137,12 @@
                   bool is_initial_navigation,
                   bool is_server_redirect,
                   bool* send_referrer) override;
-  bool WillSendRequest(blink::WebLocalFrame* frame,
-                       ui::PageTransition transition_type,
-                       const blink::WebURL& url,
-                       GURL* new_url) override;
+  bool WillSendRequest(
+      blink::WebLocalFrame* frame,
+      ui::PageTransition transition_type,
+      const blink::WebURL& url,
+      std::vector<std::unique_ptr<content::URLLoaderThrottle>>* throttles,
+      GURL* new_url) override;
   bool IsPrefetchOnly(content::RenderFrame* render_frame,
                       const blink::WebURLRequest& request) override;
   unsigned long long VisitedLinkHash(const char* canonical_url,
@@ -242,6 +245,8 @@
 
   chrome::ChromeKeySystemsProvider key_systems_provider_;
 
+  chrome::mojom::SafeBrowsingPtr safe_browsing_;
+
 #if BUILDFLAG(ENABLE_SPELLCHECK)
   std::unique_ptr<SpellCheck> spellcheck_;
 #endif
diff --git a/chrome/renderer/chrome_content_renderer_client_browsertest.cc b/chrome/renderer/chrome_content_renderer_client_browsertest.cc
index 04d9f92..db18349 100644
--- a/chrome/renderer/chrome_content_renderer_client_browsertest.cc
+++ b/chrome/renderer/chrome_content_renderer_client_browsertest.cc
@@ -18,6 +18,7 @@
 #include "chrome/test/base/chrome_render_view_test.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "content/public/child/url_loader_throttle.h"
 #include "content/public/common/content_constants.h"
 #include "content/public/renderer/render_frame.h"
 #include "content/public/renderer/render_view.h"
@@ -98,10 +99,12 @@
       "chrome-search:/thumb/%i/1",
       render_frame->GetRenderView()->GetRoutingID()));
 
+  std::vector<std::unique_ptr<content::URLLoaderThrottle>> throttles;
   GURL result;
   // Make sure the SearchBox rewrites a thumbnail request from the main frame.
   EXPECT_TRUE(client.WillSendRequest(GetMainFrame(), ui::PAGE_TRANSITION_LINK,
-                                     blink::WebURL(thumbnail_url), &result));
+                                     blink::WebURL(thumbnail_url), &throttles,
+                                     &result));
 
   // Make sure the SearchBox rewrites a thumbnail request from the iframe.
   blink::WebFrame* child_frame = GetMainFrame()->FirstChild();
@@ -110,7 +113,8 @@
   blink::WebLocalFrame* local_child =
       static_cast<blink::WebLocalFrame*>(child_frame);
   EXPECT_TRUE(client.WillSendRequest(local_child, ui::PAGE_TRANSITION_LINK,
-                                     blink::WebURL(thumbnail_url), &result));
+                                     blink::WebURL(thumbnail_url), &throttles,
+                                     &result));
 }
 
 // The tests below examine Youtube requests that use the Flash API and ensure
diff --git a/chrome/renderer/safe_browsing/safe_browsing_url_loader_throttle.cc b/chrome/renderer/safe_browsing/safe_browsing_url_loader_throttle.cc
new file mode 100644
index 0000000..514acc9
--- /dev/null
+++ b/chrome/renderer/safe_browsing/safe_browsing_url_loader_throttle.cc
@@ -0,0 +1,104 @@
+// Copyright 2017 The Chromium 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/safe_browsing/safe_browsing_url_loader_throttle.h"
+
+#include "base/logging.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "net/url_request/redirect_info.h"
+
+namespace safe_browsing {
+
+SafeBrowsingURLLoaderThrottle::SafeBrowsingURLLoaderThrottle(
+    chrome::mojom::SafeBrowsing* safe_browsing,
+    int render_frame_id)
+    : safe_browsing_(safe_browsing),
+      render_frame_id_(render_frame_id),
+      weak_factory_(this) {}
+
+SafeBrowsingURLLoaderThrottle::~SafeBrowsingURLLoaderThrottle() = default;
+
+void SafeBrowsingURLLoaderThrottle::WillStartRequest(
+    const GURL& url,
+    int load_flags,
+    content::ResourceType resource_type,
+    bool* defer) {
+  DCHECK_EQ(0u, pending_checks_);
+  DCHECK(!blocked_);
+  DCHECK(!url_checker_);
+
+  pending_checks_++;
+  // Use a weak pointer to self because |safe_browsing_| is not owned by this
+  // object.
+  safe_browsing_->CreateCheckerAndCheck(
+      render_frame_id_, mojo::MakeRequest(&url_checker_), url, load_flags,
+      resource_type,
+      base::BindOnce(&SafeBrowsingURLLoaderThrottle::OnCheckUrlResult,
+                     weak_factory_.GetWeakPtr()));
+  safe_browsing_ = nullptr;
+
+  url_checker_.set_connection_error_handler(
+      base::Bind(&SafeBrowsingURLLoaderThrottle::OnConnectionError,
+                 base::Unretained(this)));
+}
+
+void SafeBrowsingURLLoaderThrottle::WillRedirectRequest(
+    const net::RedirectInfo& redirect_info,
+    bool* defer) {
+  // If |blocked_| is true, the resource load has been canceled and there
+  // shouldn't be such a notification.
+  DCHECK(!blocked_);
+
+  if (!url_checker_) {
+    DCHECK_EQ(0u, pending_checks_);
+    return;
+  }
+
+  pending_checks_++;
+  url_checker_->CheckUrl(
+      redirect_info.new_url,
+      base::BindOnce(&SafeBrowsingURLLoaderThrottle::OnCheckUrlResult,
+                     base::Unretained(this)));
+}
+
+void SafeBrowsingURLLoaderThrottle::WillProcessResponse(bool* defer) {
+  // If |blocked_| is true, the resource load has been canceled and there
+  // shouldn't be such a notification.
+  DCHECK(!blocked_);
+
+  if (pending_checks_ > 0)
+    *defer = true;
+}
+
+void SafeBrowsingURLLoaderThrottle::OnCheckUrlResult(bool safe) {
+  if (blocked_ || !url_checker_)
+    return;
+
+  DCHECK_LT(0u, pending_checks_);
+  pending_checks_--;
+
+  if (safe) {
+    if (pending_checks_ == 0) {
+      // The resource load is not necessarily deferred, in that case Resume() is
+      // a no-op.
+      delegate_->Resume();
+    }
+  } else {
+    url_checker_.reset();
+    blocked_ = true;
+    pending_checks_ = 0;
+    delegate_->CancelWithError(net::ERR_ABORTED);
+  }
+}
+
+void SafeBrowsingURLLoaderThrottle::OnConnectionError() {
+  DCHECK(!blocked_);
+
+  // If a service-side disconnect happens, treat all URLs as if they are safe.
+  url_checker_.reset();
+  pending_checks_ = 0;
+  delegate_->Resume();
+}
+
+}  // namespace safe_browsing
diff --git a/chrome/renderer/safe_browsing/safe_browsing_url_loader_throttle.h b/chrome/renderer/safe_browsing/safe_browsing_url_loader_throttle.h
new file mode 100644
index 0000000..01a599f
--- /dev/null
+++ b/chrome/renderer/safe_browsing/safe_browsing_url_loader_throttle.h
@@ -0,0 +1,60 @@
+// Copyright 2017 The Chromium 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_SAFE_BROWSING_SAFE_BROWSING_URL_LOADER_THROTTLE_H_
+#define CHROME_RENDERER_SAFE_BROWSING_SAFE_BROWSING_URL_LOADER_THROTTLE_H_
+
+#include "base/memory/weak_ptr.h"
+#include "chrome/common/safe_browsing.mojom.h"
+#include "content/public/child/url_loader_throttle.h"
+
+namespace chrome {
+namespace mojom {
+class SafeBrowsing;
+}
+}
+
+namespace safe_browsing {
+
+// SafeBrowsingURLLoaderThrottle queries SafeBrowsing to determine whether the
+// URL and also redirect URLs are safe to load. It defers response processing
+// until all URL checks are completed; cancels the load if any URLs turn out to
+// be bad.
+class SafeBrowsingURLLoaderThrottle : public content::URLLoaderThrottle {
+ public:
+  // |safe_browsing| must stay alive until WillStartRequest() (if it is called)
+  // or the end of this object.
+  // |render_frame_id| is used for displaying SafeBrowsing UI when necessary.
+  SafeBrowsingURLLoaderThrottle(chrome::mojom::SafeBrowsing* safe_browsing,
+                                int render_frame_id);
+  ~SafeBrowsingURLLoaderThrottle() override;
+
+  // content::URLLoaderThrottle implementation.
+  void WillStartRequest(const GURL& url,
+                        int load_flags,
+                        content::ResourceType resource_type,
+                        bool* defer) override;
+  void WillRedirectRequest(const net::RedirectInfo& redirect_info,
+                           bool* defer) override;
+  void WillProcessResponse(bool* defer) override;
+
+ private:
+  void OnCheckUrlResult(bool safe);
+
+  void OnConnectionError();
+
+  chrome::mojom::SafeBrowsing* safe_browsing_;
+  const int render_frame_id_;
+
+  chrome::mojom::SafeBrowsingUrlCheckerPtr url_checker_;
+
+  size_t pending_checks_ = 0;
+  bool blocked_ = false;
+
+  base::WeakPtrFactory<SafeBrowsingURLLoaderThrottle> weak_factory_;
+};
+
+}  // namespace safe_browsing
+
+#endif  // CHROME_RENDERER_SAFE_BROWSING_SAFE_BROWSING_URL_LOADER_THROTTLE_H_
diff --git a/chrome/service/cloud_print/cloud_print_proxy.cc b/chrome/service/cloud_print/cloud_print_proxy.cc
index 4ba9616..0240406 100644
--- a/chrome/service/cloud_print/cloud_print_proxy.cc
+++ b/chrome/service/cloud_print/cloud_print_proxy.cc
@@ -33,19 +33,19 @@
 }
 
 CloudPrintProxy::~CloudPrintProxy() {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   ShutdownBackend();
 }
 
 void CloudPrintProxy::Initialize(ServiceProcessPrefs* service_prefs,
                                  Client* client) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   service_prefs_ = service_prefs;
   client_ = client;
 }
 
 void CloudPrintProxy::EnableForUser() {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (!CreateBackend())
     return;
   DCHECK(backend_.get());
@@ -78,7 +78,7 @@
     const std::string& robot_email,
     const std::string& user_email,
     const base::DictionaryValue& user_settings) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   ShutdownBackend();
   std::string proxy_id(
@@ -103,7 +103,7 @@
 }
 
 bool CloudPrintProxy::CreateBackend() {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (backend_.get())
     return false;
 
@@ -127,7 +127,7 @@
 }
 
 void CloudPrintProxy::UnregisterPrintersAndDisableForUser() {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (backend_.get()) {
     // Try getting auth and printers info from the backend.
     // We'll get notified in this case.
@@ -139,7 +139,7 @@
 }
 
 void CloudPrintProxy::DisableForUser() {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   user_email_.clear();
   enabled_ = false;
   if (client_) {
@@ -178,7 +178,7 @@
     const std::string& robot_oauth_refresh_token,
     const std::string& robot_email,
     const std::string& user_email) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   service_prefs_->SetString(prefs::kCloudPrintRobotRefreshToken,
                             robot_oauth_refresh_token);
   service_prefs_->SetString(prefs::kCloudPrintRobotEmail,
@@ -203,7 +203,7 @@
 }
 
 void CloudPrintProxy::OnAuthenticationFailed() {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // Don't disable permanently. Could be just connection issue.
   ShutdownBackend();
   if (client_) {
@@ -233,7 +233,7 @@
 }
 
 void CloudPrintProxy::OnXmppPingUpdated(int ping_timeout) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   service_prefs_->SetInt(prefs::kCloudPrintXmppPingTimeout, ping_timeout);
   service_prefs_->WritePrefs();
 }
@@ -245,7 +245,7 @@
 }
 
 void CloudPrintProxy::ShutdownBackend() {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (backend_.get())
     backend_->Shutdown();
   backend_.reset();
diff --git a/chrome/service/cloud_print/cloud_print_proxy.h b/chrome/service/cloud_print/cloud_print_proxy.h
index 257e21d..da9395f 100644
--- a/chrome/service/cloud_print/cloud_print_proxy.h
+++ b/chrome/service/cloud_print/cloud_print_proxy.h
@@ -11,7 +11,7 @@
 #include <vector>
 
 #include "base/macros.h"
-#include "base/threading/non_thread_safe.h"
+#include "base/sequence_checker.h"
 #include "chrome/service/cloud_print/cloud_print_proxy_backend.h"
 #include "chrome/service/cloud_print/cloud_print_wipeout.h"
 
@@ -24,8 +24,7 @@
 // CloudPrintProxy is the layer between the service process UI thread
 // and the cloud print proxy backend.
 class CloudPrintProxy : public CloudPrintProxyFrontend,
-                        public CloudPrintWipeout::Client,
-                        public base::NonThreadSafe {
+                        public CloudPrintWipeout::Client {
  public:
   class Client {
    public:
@@ -99,6 +98,8 @@
   // This is a cleanup class for unregistering printers on proxy disable.
   std::unique_ptr<CloudPrintWipeout> wipeout_;
 
+  SEQUENCE_CHECKER(sequence_checker_);
+
   DISALLOW_COPY_AND_ASSIGN(CloudPrintProxy);
 };
 
diff --git a/chrome/service/cloud_print/cloud_print_token_store.cc b/chrome/service/cloud_print/cloud_print_token_store.cc
index dd34e4f5..84006ee 100644
--- a/chrome/service/cloud_print/cloud_print_token_store.cc
+++ b/chrome/service/cloud_print/cloud_print_token_store.cc
@@ -24,11 +24,12 @@
 }
 
 CloudPrintTokenStore::~CloudPrintTokenStore() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   lazy_tls.Pointer()->Set(NULL);
 }
 
 void CloudPrintTokenStore::SetToken(const std::string& token) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   token_ = token;
 }
 
diff --git a/chrome/service/cloud_print/cloud_print_token_store.h b/chrome/service/cloud_print/cloud_print_token_store.h
index 767619b5..b61ed9ee 100644
--- a/chrome/service/cloud_print/cloud_print_token_store.h
+++ b/chrome/service/cloud_print/cloud_print_token_store.h
@@ -8,14 +8,14 @@
 #include <string>
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/threading/non_thread_safe.h"
+#include "base/sequence_checker.h"
 
 // This class serves as the single repository for cloud print auth tokens. This
 // is only used within the CloudPrintProxyCoreThread.
 
 namespace cloud_print {
 
-class CloudPrintTokenStore : public base::NonThreadSafe {
+class CloudPrintTokenStore {
  public:
   // Returns the CloudPrintTokenStore instance for this thread. Will be NULL
   // if no instance was created in this thread before.
@@ -26,13 +26,15 @@
 
   void SetToken(const std::string& token);
   std::string token() const {
-    DCHECK(CalledOnValidThread());
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     return token_;
   }
 
  private:
   std::string token_;
 
+  SEQUENCE_CHECKER(sequence_checker_);
+
   DISALLOW_COPY_AND_ASSIGN(CloudPrintTokenStore);
 };
 
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 2b006a2..355a01da 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -3657,6 +3657,7 @@
       "../browser/ui/webui/options/pepper_flash_content_settings_utils_unittest.cc",
       "../browser/ui/webui/options/sync_setup_handler_unittest.cc",
       "../browser/ui/webui/settings/downloads_handler_unittest.cc",
+      "../browser/ui/webui/settings/md_settings_ui_unittest.cc",
       "../browser/ui/webui/settings/metrics_reporting_handler_unittest.cc",
       "../browser/ui/webui/settings/people_handler_unittest.cc",
       "../browser/ui/webui/settings/profile_info_handler_unittest.cc",
diff --git a/chrome/test/base/in_process_browser_test.cc b/chrome/test/base/in_process_browser_test.cc
index 8d8cac9..73c21567 100644
--- a/chrome/test/base/in_process_browser_test.cc
+++ b/chrome/test/base/in_process_browser_test.cc
@@ -220,7 +220,7 @@
 
 #if defined(OS_CHROMEOS)
   // Make sure that the log directory exists.
-  base::FilePath log_dir = logging::GetSessionLogFile(*command_line).DirName();
+  base::FilePath log_dir = logging::GetSessionLogDir(*command_line);
   base::CreateDirectory(log_dir);
   // Disable IME extension loading to avoid many browser tests failures.
   chromeos::input_method::DisableExtensionLoading();
diff --git a/chrome/test/data/extensions/api_test/automation/sites/attributes.html b/chrome/test/data/extensions/api_test/automation/sites/attributes.html
index 7efb7145b..4d19b2d 100644
--- a/chrome/test/data/extensions/api_test/automation/sites/attributes.html
+++ b/chrome/test/data/extensions/api_test/automation/sites/attributes.html
@@ -76,6 +76,8 @@
   <div id="check-test-2" aria-label="check-test-2" role="checkbox" aria-checked="false">Unchecked</div>
   <div id="check-test-3" aria-label="check-test-3" role="checkbox" aria-checked="mixed">Mixed</div>
   <div id="check-test-4" aria-label="check-test-4" aria-checked="true">Not a checkbox</div>
+  <div id="check-test-5" aria-label="check-test-5" role="treeitem" aria-checked="true">Checked treeitem</div>
+  <div id="check-test-6" aria-label="check-test-6" role="button" aria-pressed="true">Pressed button</div>
 
   <!-- htmlTag attribute -->
   <figure>Go figure!</figure>
diff --git a/chrome/test/data/extensions/api_test/automation/tests/tabs/attributes.js b/chrome/test/data/extensions/api_test/automation/tests/tabs/attributes.js
index e82bdaf..ef035457 100644
--- a/chrome/test/data/extensions/api_test/automation/tests/tabs/attributes.js
+++ b/chrome/test/data/extensions/api_test/automation/tests/tabs/attributes.js
@@ -298,6 +298,16 @@
     assertTrue(Boolean(checkTest4));
     assertEq(checkTest4.checked, undefined);
 
+    // Treeitem can be checked
+    var checkTest5 = rootNode.find({ attributes: { name: 'check-test-5' } });
+    assertTrue(Boolean(checkTest5));
+    assertEq(checkTest5.checked, 'true');
+
+    // button with aria-pressed shows up as checked
+    var checkTest6 = rootNode.find({ attributes: { name: 'check-test-6' } });
+    assertTrue(Boolean(checkTest6));
+    assertEq(checkTest6.checked, 'true');
+
     chrome.test.succeed();
   },
 
diff --git a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastBrowserHelper.java b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastBrowserHelper.java
index d587c624..c4c39a1b4 100644
--- a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastBrowserHelper.java
+++ b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastBrowserHelper.java
@@ -68,7 +68,7 @@
             Log.d(TAG, "Loading BrowserStartupController...");
             BrowserStartupController.get(LibraryProcessType.PROCESS_BROWSER)
                     .startBrowserProcessesSync(false);
-            NetworkChangeNotifier.init(context);
+            NetworkChangeNotifier.init();
             // Cast shell always expects to receive notifications to track network state.
             NetworkChangeNotifier.registerToReceiveNotificationsAlways();
             sIsBrowserInitialized = true;
diff --git a/chromecast/browser/metrics/OWNERS b/chromecast/browser/metrics/OWNERS
index 73e387e..292eb32f1 100644
--- a/chromecast/browser/metrics/OWNERS
+++ b/chromecast/browser/metrics/OWNERS
@@ -1,6 +1,4 @@
 # components/metrics OWNERS for review of Chromecast metrics code
-asvitkine@chromium.org
-mpearson@chromium.org
-isherman@chromium.org
+file://components/metrics/OWNERS
 
 # COMPONENT: Internals>Metrics
diff --git a/chromecast/browser/metrics/cast_metrics_service_client.cc b/chromecast/browser/metrics/cast_metrics_service_client.cc
index c7ecddf6..d769bf7 100644
--- a/chromecast/browser/metrics/cast_metrics_service_client.cc
+++ b/chromecast/browser/metrics/cast_metrics_service_client.cc
@@ -243,7 +243,9 @@
     return command_line->GetSwitchValueASCII(
         switches::kOverrideMetricsUploadUrl);
   }
-  return ::metrics::MetricsServiceClient::GetMetricsServerUrl();
+  // Note: This uses the old metrics service URL because some server-side
+  // provisioning is needed to support the extra Cast traffic on the new URL.
+  return ::metrics::kOldMetricsServerUrl;
 }
 
 std::unique_ptr<::metrics::MetricsLogUploader>
diff --git a/chromeos/components/tether/BUILD.gn b/chromeos/components/tether/BUILD.gn
index 6f22f8cd..3a5c33b2 100644
--- a/chromeos/components/tether/BUILD.gn
+++ b/chromeos/components/tether/BUILD.gn
@@ -24,6 +24,8 @@
     "connect_tethering_operation.h",
     "device_id_tether_network_guid_map.cc",
     "device_id_tether_network_guid_map.h",
+    "device_status_util.cc",
+    "device_status_util.h",
     "disconnect_tethering_operation.cc",
     "disconnect_tethering_operation.h",
     "host_scan_cache.cc",
@@ -141,6 +143,7 @@
     "ble_connection_manager_unittest.cc",
     "ble_scanner_unittest.cc",
     "connect_tethering_operation_unittest.cc",
+    "device_status_util_unittest.cc",
     "disconnect_tethering_operation_unittest.cc",
     "host_scan_cache_unittest.cc",
     "host_scan_device_prioritizer_unittest.cc",
diff --git a/chromeos/components/tether/device_status_util.cc b/chromeos/components/tether/device_status_util.cc
new file mode 100644
index 0000000..5d134a9
--- /dev/null
+++ b/chromeos/components/tether/device_status_util.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 "chromeos/components/tether/device_status_util.h"
+
+namespace chromeos {
+
+namespace tether {
+
+namespace {
+
+const char kDefaultCellCarrierName[] = "unknown-carrier";
+
+// Android signal strength is measured between 0 and 4 (inclusive), but Chrome
+// OS signal strength is measured between 0 and 100 (inclusive). In order to
+// convert between Android signal strength to Chrome OS signal strength, the
+// value must be multiplied by the below value.
+const int32_t kAndroidTetherHostToChromeOSSignalStrengthMultiplier = 25;
+
+int32_t ForceBetweenZeroAndOneHundred(int32_t value) {
+  return std::min(std::max(value, 0), 100);
+}
+
+}  // namespace
+
+void NormalizeDeviceStatus(const DeviceStatus& status,
+                           std::string* carrier_out,
+                           int32_t* battery_percentage_out,
+                           int32_t* signal_strength_out) {
+  // Use a sentinel value if carrier information is not available. This value is
+  // special-cased and replaced with a localized string in the settings UI.
+  if (carrier_out) {
+    *carrier_out =
+        (!status.has_cell_provider() || status.cell_provider().empty())
+            ? kDefaultCellCarrierName
+            : status.cell_provider();
+  }
+
+  // If battery or signal strength are missing, assume they are 100. For
+  // battery percentage, force the value to be between 0 and 100. For signal
+  // strength, convert from Android signal strength to Chrome OS signal
+  // strength and force the value to be between 0 and 100.
+  if (battery_percentage_out) {
+    *battery_percentage_out =
+        status.has_battery_percentage()
+            ? ForceBetweenZeroAndOneHundred(status.battery_percentage())
+            : 100;
+  }
+  if (signal_strength_out) {
+    *signal_strength_out =
+        status.has_connection_strength()
+            ? ForceBetweenZeroAndOneHundred(
+                  kAndroidTetherHostToChromeOSSignalStrengthMultiplier *
+                  status.connection_strength())
+            : 100;
+  }
+}
+
+}  // namespace tether
+
+}  // namespace chromeos
diff --git a/chromeos/components/tether/device_status_util.h b/chromeos/components/tether/device_status_util.h
new file mode 100644
index 0000000..4b0c0a0
--- /dev/null
+++ b/chromeos/components/tether/device_status_util.h
@@ -0,0 +1,39 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_COMPONENTS_TETHER_DEVICE_STATUS_UTIL_H_
+#define CHROMEOS_COMPONENTS_TETHER_DEVICE_STATUS_UTIL_H_
+
+#include "chromeos/components/tether/proto/tether.pb.h"
+
+namespace chromeos {
+
+namespace tether {
+
+// Normalizes the values contained in |device_status| and outputs the normalized
+// values for carrier, battery percentage, and signal strength. The values are
+// normalized according to the following rules:
+//   (1) Carrier: If the proto's cell_provider field is present and non-empty,
+//       it is output; otherwise, the "unknown-carrier" constant is output.
+//   (2) Battery percentage: If the proto's battery_percentage field is present
+//       and within the range [0, 100], it is output; if the field is present
+//       but not in [0, 100], 0 is output if the input is <0 and 100 is output
+//       if the input is >100; if the field is not present, 100 is output.
+//   (3) Signal strength: If the proto's connection_strength field is present
+//       and within the range [0, 4], it is multiplied by 25 and output in a new
+//       range [0, 100]; if the field is present but not in [0, 4], 0 is output
+//       if the input is <0 and 100 is output if the input >4; if the field is
+//       not present, 100 is output. Note that the multipier is needed because
+//       Android's connection strength is a value from 0 to 4, while Chrome OS's
+//       signal strength ranges from 0 to 100.
+void NormalizeDeviceStatus(const DeviceStatus& status,
+                           std::string* carrier_out,
+                           int32_t* battery_percentage_out,
+                           int32_t* signal_strength_out);
+
+}  // namespace tether
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_COMPONENTS_TETHER_DEVICE_STATUS_UTIL_H_
diff --git a/chromeos/components/tether/device_status_util_unittest.cc b/chromeos/components/tether/device_status_util_unittest.cc
new file mode 100644
index 0000000..3aa05ab
--- /dev/null
+++ b/chromeos/components/tether/device_status_util_unittest.cc
@@ -0,0 +1,155 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/components/tether/device_status_util.h"
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "chromeos/components/tether/fake_tether_host_fetcher.h"
+#include "components/cryptauth/remote_device.h"
+#include "components/cryptauth/remote_device_test_util.h"
+#include "components/prefs/testing_pref_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+
+namespace tether {
+
+namespace {
+
+const char kDoNotSetStringField[] = "doNotSetField";
+const int kDoNotSetIntField = -100;
+
+// Creates a DeviceStatus object using the parameters provided. If
+// |kDoNotSetStringField| or |kDoNotSetIntField| are passed, these fields will
+// not be set in the output.
+DeviceStatus CreateFakeDeviceStatus(const std::string& cell_provider_name,
+                                    int battery_percentage,
+                                    int connection_strength) {
+  // TODO(khorimoto): Once a ConnectedWifiSsid field is added as a property of
+  // Tether networks, give an option to pass a parameter for that field as well.
+  WifiStatus wifi_status;
+  wifi_status.set_status_code(
+      WifiStatus_StatusCode::WifiStatus_StatusCode_CONNECTED);
+  wifi_status.set_ssid("Google A");
+
+  DeviceStatus device_status;
+  if (battery_percentage != kDoNotSetIntField) {
+    device_status.set_battery_percentage(battery_percentage);
+  }
+  if (cell_provider_name != kDoNotSetStringField) {
+    device_status.set_cell_provider(cell_provider_name);
+  }
+  if (connection_strength != kDoNotSetIntField) {
+    device_status.set_connection_strength(connection_strength);
+  }
+
+  device_status.mutable_wifi_status()->CopyFrom(wifi_status);
+
+  return device_status;
+}
+
+}  // namespace
+
+class DeviceStatusUtilTest : public testing::Test {
+ public:
+  DeviceStatusUtilTest() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DeviceStatusUtilTest);
+};
+
+TEST_F(DeviceStatusUtilTest, TestNotPresent) {
+  DeviceStatus status =
+      CreateFakeDeviceStatus(kDoNotSetStringField /* cell_provider_name */,
+                             kDoNotSetIntField /* battery_percentage */,
+                             kDoNotSetIntField /* connection_strength */);
+
+  std::string carrier;
+  int32_t battery_percentage;
+  int32_t signal_strength;
+
+  NormalizeDeviceStatus(status, &carrier, &battery_percentage,
+                        &signal_strength);
+
+  EXPECT_EQ("unknown-carrier", carrier);
+  EXPECT_EQ(100, battery_percentage);
+  EXPECT_EQ(100, signal_strength);
+}
+
+TEST_F(DeviceStatusUtilTest, TestEmptyCellProvider) {
+  DeviceStatus status = CreateFakeDeviceStatus(
+      "" /* cell_provider_name */, kDoNotSetIntField /* battery_percentage */,
+      kDoNotSetIntField /* connection_strength */);
+
+  std::string carrier;
+  int32_t battery_percentage;
+  int32_t signal_strength;
+
+  NormalizeDeviceStatus(status, &carrier, &battery_percentage,
+                        &signal_strength);
+
+  EXPECT_EQ("unknown-carrier", carrier);
+  EXPECT_EQ(100, battery_percentage);
+  EXPECT_EQ(100, signal_strength);
+}
+
+TEST_F(DeviceStatusUtilTest, TestBelowMinValue) {
+  DeviceStatus status = CreateFakeDeviceStatus(
+      "cellProvider" /* cell_provider_name */, -1 /* battery_percentage */,
+      -1 /* connection_strength */);
+
+  std::string carrier;
+  int32_t battery_percentage;
+  int32_t signal_strength;
+
+  NormalizeDeviceStatus(status, &carrier, &battery_percentage,
+                        &signal_strength);
+
+  EXPECT_EQ("cellProvider", carrier);
+  EXPECT_EQ(0, battery_percentage);
+  EXPECT_EQ(0, signal_strength);
+}
+
+TEST_F(DeviceStatusUtilTest, TestAboveMaxValue) {
+  DeviceStatus status = CreateFakeDeviceStatus(
+      "cellProvider" /* cell_provider_name */, 101 /* battery_percentage */,
+      5 /* connection_strength */);
+
+  std::string carrier;
+  int32_t battery_percentage;
+  int32_t signal_strength;
+
+  NormalizeDeviceStatus(status, &carrier, &battery_percentage,
+                        &signal_strength);
+
+  EXPECT_EQ("cellProvider", carrier);
+  EXPECT_EQ(100, battery_percentage);
+  EXPECT_EQ(100, signal_strength);
+}
+
+TEST_F(DeviceStatusUtilTest, TestValidValues) {
+  DeviceStatus status = CreateFakeDeviceStatus(
+      "cellProvider" /* cell_provider_name */, 50 /* battery_percentage */,
+      2 /* connection_strength */);
+
+  std::string carrier;
+  int32_t battery_percentage;
+  int32_t signal_strength;
+
+  NormalizeDeviceStatus(status, &carrier, &battery_percentage,
+                        &signal_strength);
+
+  EXPECT_EQ("cellProvider", carrier);
+  EXPECT_EQ(50, battery_percentage);
+  EXPECT_EQ(50, signal_strength);
+}
+
+}  // namespace tether
+
+}  // namespace cryptauth
diff --git a/chromeos/components/tether/disconnect_tethering_operation.cc b/chromeos/components/tether/disconnect_tethering_operation.cc
index 72b2218..1786946 100644
--- a/chromeos/components/tether/disconnect_tethering_operation.cc
+++ b/chromeos/components/tether/disconnect_tethering_operation.cc
@@ -86,6 +86,10 @@
   return MessageType::DISCONNECT_TETHERING_REQUEST;
 }
 
+bool DisconnectTetheringOperation::ShouldWaitForResponse() {
+  return false;
+}
+
 }  // namespace tether
 
 }  // namespace chromeos
diff --git a/chromeos/components/tether/disconnect_tethering_operation.h b/chromeos/components/tether/disconnect_tethering_operation.h
index 0a72b47..6e693c7 100644
--- a/chromeos/components/tether/disconnect_tethering_operation.h
+++ b/chromeos/components/tether/disconnect_tethering_operation.h
@@ -58,6 +58,7 @@
       const cryptauth::RemoteDevice& remote_device) override;
   void OnOperationFinished() override;
   MessageType GetMessageTypeForConnection() override;
+  bool ShouldWaitForResponse() override;
 
  private:
   friend class DisconnectTetheringOperationTest;
diff --git a/chromeos/components/tether/host_scanner.cc b/chromeos/components/tether/host_scanner.cc
index 31308e8..74eb755 100644
--- a/chromeos/components/tether/host_scanner.cc
+++ b/chromeos/components/tether/host_scanner.cc
@@ -8,6 +8,7 @@
 
 #include "base/bind.h"
 #include "chromeos/components/tether/device_id_tether_network_guid_map.h"
+#include "chromeos/components/tether/device_status_util.h"
 #include "chromeos/components/tether/host_scan_cache.h"
 #include "chromeos/components/tether/tether_host_fetcher.h"
 #include "chromeos/network/network_state.h"
@@ -17,22 +18,6 @@
 
 namespace tether {
 
-namespace {
-
-const char kDefaultCellCarrierName[] = "unknown-carrier";
-
-// Android signal strength is measured between 0 and 4 (inclusive), but Chrome
-// OS signal strength is measured between 0 and 100 (inclusive). In order to
-// convert between Android signal strength to Chrome OS signal strength, the
-// value must be multiplied by the below value.
-const int32_t kAndroidTetherHostToChromeOSSignalStrengthMultiplier = 25;
-
-int32_t ForceBetweenZeroAndOneHundred(int32_t value) {
-  return std::min(std::max(value, 0), 100);
-}
-
-}  // namespace
-
 HostScanner::HostScanner(
     TetherHostFetcher* tether_host_fetcher,
     BleConnectionManager* connection_manager,
@@ -142,27 +127,11 @@
   const cryptauth::RemoteDevice& remote_device =
       scanned_device_info.remote_device;
 
-  // Use a sentinel value if carrier information is not available. This value is
-  // special-cased and replaced with a localized string in the settings UI.
-  const std::string carrier =
-      (!status.has_cell_provider() || status.cell_provider().empty())
-          ? kDefaultCellCarrierName
-          : status.cell_provider();
-
-  // If battery or signal strength are missing, assume they are 100. For
-  // battery percentage, force the value to be between 0 and 100. For signal
-  // strength, convert from Android signal strength to Chrome OS signal
-  // strength and force the value to be between 0 and 100.
-  const int32_t battery_percentage =
-      status.has_battery_percentage()
-          ? ForceBetweenZeroAndOneHundred(status.battery_percentage())
-          : 100;
-  const int32_t signal_strength =
-      status.has_connection_strength()
-          ? ForceBetweenZeroAndOneHundred(
-                kAndroidTetherHostToChromeOSSignalStrengthMultiplier *
-                status.connection_strength())
-          : 100;
+  std::string carrier;
+  int32_t battery_percentage;
+  int32_t signal_strength;
+  NormalizeDeviceStatus(status, &carrier, &battery_percentage,
+                        &signal_strength);
 
   host_scan_cache_->SetHostScanResult(
       device_id_tether_network_guid_map_->GetTetherNetworkGuidForDeviceId(
diff --git a/chromeos/components/tether/message_transfer_operation.cc b/chromeos/components/tether/message_transfer_operation.cc
index d9d75cf..ab01676 100644
--- a/chromeos/components/tether/message_transfer_operation.cc
+++ b/chromeos/components/tether/message_transfer_operation.cc
@@ -7,6 +7,7 @@
 #include <set>
 
 #include "chromeos/components/tether/message_wrapper.h"
+#include "chromeos/components/tether/timer_factory.h"
 #include "components/proximity_auth/logging/logging.h"
 
 namespace chromeos {
@@ -35,12 +36,17 @@
 // static
 uint32_t MessageTransferOperation::kMaxConnectionAttemptsPerDevice = 3;
 
+// static
+uint32_t MessageTransferOperation::kDefaultResponseTimeoutSeconds = 10;
+
 MessageTransferOperation::MessageTransferOperation(
     const std::vector<cryptauth::RemoteDevice>& devices_to_connect,
     BleConnectionManager* connection_manager)
     : remote_devices_(RemoveDuplicatesFromVector(devices_to_connect)),
       connection_manager_(connection_manager),
-      initialized_(false) {}
+      timer_factory_(base::MakeUnique<TimerFactory>()),
+      initialized_(false),
+      weak_ptr_factory_(this) {}
 
 MessageTransferOperation::~MessageTransferOperation() {
   connection_manager_->RemoveObserver(this);
@@ -63,6 +69,9 @@
     cryptauth::SecureChannel::Status status;
     if (connection_manager_->GetStatusForDevice(remote_device, &status) &&
         status == cryptauth::SecureChannel::Status::AUTHENTICATED) {
+      if (ShouldWaitForResponse())
+        StartResponseTimerForDevice(remote_device);
+
       OnDeviceAuthenticated(remote_device);
     }
   }
@@ -81,6 +90,9 @@
   }
 
   if (new_status == cryptauth::SecureChannel::Status::AUTHENTICATED) {
+    if (ShouldWaitForResponse())
+      StartResponseTimerForDevice(remote_device);
+
     OnDeviceAuthenticated(remote_device);
   } else if (old_status == cryptauth::SecureChannel::Status::AUTHENTICATING) {
     // If authentication fails, account details (e.g., BeaconSeeds) are not
@@ -139,6 +151,9 @@
   remote_devices_.erase(std::remove(remote_devices_.begin(),
                                     remote_devices_.end(), remote_device),
                         remote_devices_.end());
+  if (ShouldWaitForResponse())
+    StopResponseTimerForDeviceIfRunning(remote_device);
+
   connection_manager_->UnregisterRemoteDevice(remote_device,
                                               GetMessageTypeForConnection());
 
@@ -154,6 +169,56 @@
                                    message_wrapper->ToRawMessage());
 }
 
+bool MessageTransferOperation::ShouldWaitForResponse() {
+  return true;
+}
+
+uint32_t MessageTransferOperation::GetResponseTimeoutSeconds() {
+  return MessageTransferOperation::kDefaultResponseTimeoutSeconds;
+}
+
+void MessageTransferOperation::SetTimerFactoryForTest(
+    std::unique_ptr<TimerFactory> timer_factory_for_test) {
+  timer_factory_ = std::move(timer_factory_for_test);
+}
+
+void MessageTransferOperation::StartResponseTimerForDevice(
+    const cryptauth::RemoteDevice& remote_device) {
+  DCHECK(ShouldWaitForResponse());
+
+  PA_LOG(INFO) << "Starting timer to wait for response to message type "
+               << GetMessageTypeForConnection() << " from device with ID "
+               << remote_device.GetTruncatedDeviceIdForLogs() << ".";
+
+  remote_device_to_timer_map_.emplace(remote_device,
+                                      timer_factory_->CreateOneShotTimer());
+  remote_device_to_timer_map_[remote_device]->Start(
+      FROM_HERE, base::TimeDelta::FromSeconds(GetResponseTimeoutSeconds()),
+      base::Bind(&MessageTransferOperation::OnResponseTimeout,
+                 weak_ptr_factory_.GetWeakPtr(), remote_device));
+}
+
+void MessageTransferOperation::StopResponseTimerForDeviceIfRunning(
+    const cryptauth::RemoteDevice& remote_device) {
+  DCHECK(ShouldWaitForResponse());
+
+  if (!remote_device_to_timer_map_[remote_device])
+    return;
+
+  remote_device_to_timer_map_[remote_device]->Stop();
+  remote_device_to_timer_map_.erase(remote_device);
+}
+
+void MessageTransferOperation::OnResponseTimeout(
+    const cryptauth::RemoteDevice& remote_device) {
+  PA_LOG(WARNING) << "Timed out while waiting for response to message type "
+                  << GetMessageTypeForConnection() << " from device with ID "
+                  << remote_device.GetTruncatedDeviceIdForLogs() << ".";
+
+  remote_device_to_timer_map_.erase(remote_device);
+  UnregisterDevice(remote_device);
+}
+
 }  // namespace tether
 
 }  // namespace chromeos
diff --git a/chromeos/components/tether/message_transfer_operation.h b/chromeos/components/tether/message_transfer_operation.h
index 32652140..947076a 100644
--- a/chromeos/components/tether/message_transfer_operation.h
+++ b/chromeos/components/tether/message_transfer_operation.h
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "base/timer/timer.h"
 #include "chromeos/components/tether/ble_connection_manager.h"
 
 namespace chromeos {
@@ -16,6 +17,7 @@
 namespace tether {
 
 class MessageWrapper;
+class TimerFactory;
 
 // Abstract base class used for operations which send and/or receive messages
 // from remote devices.
@@ -70,6 +72,16 @@
   // Returns the type of message that this operation intends to send.
   virtual MessageType GetMessageTypeForConnection() = 0;
 
+  // Returns true if we should wait for a response from host devices. Note
+  // that if ShouldWaitForResponse() returns true and a response is not received
+  // within the amount of time returned by GetResponseTimeoutSeconds() after a
+  // host device authenticates, that host device will be unregistered.
+  virtual bool ShouldWaitForResponse();
+
+  // The number of seconds that we should wait for a response from the host. If
+  // ShouldWaitForResponse() returns false, this method is never used.
+  virtual uint32_t GetResponseTimeoutSeconds();
+
   std::vector<cryptauth::RemoteDevice>& remote_devices() {
     return remote_devices_;
   }
@@ -82,12 +94,31 @@
 
   static uint32_t kMaxConnectionAttemptsPerDevice;
 
+  // The default number of seconds the client should generally wait for a
+  // response from the host once an authenticated connection is established.
+  // Once this amount of time passes, the connection will be closed. Subclasses
+  // of MessageTransferOperation should override GetResponseTimeoutSeconds()
+  // if they desire a different duration.
+  static uint32_t kDefaultResponseTimeoutSeconds;
+
+  void SetTimerFactoryForTest(
+      std::unique_ptr<TimerFactory> timer_factory_for_test);
+  void StartResponseTimerForDevice(
+      const cryptauth::RemoteDevice& remote_device);
+  void StopResponseTimerForDeviceIfRunning(
+      const cryptauth::RemoteDevice& remote_device);
+  void OnResponseTimeout(const cryptauth::RemoteDevice& remote_device);
+
   std::vector<cryptauth::RemoteDevice> remote_devices_;
   BleConnectionManager* connection_manager_;
+  std::unique_ptr<TimerFactory> timer_factory_;
 
   bool initialized_;
   std::map<cryptauth::RemoteDevice, uint32_t>
       remote_device_to_num_attempts_map_;
+  std::map<cryptauth::RemoteDevice, std::unique_ptr<base::Timer>>
+      remote_device_to_timer_map_;
+  base::WeakPtrFactory<MessageTransferOperation> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(MessageTransferOperation);
 };
diff --git a/chromeos/components/tether/message_transfer_operation_unittest.cc b/chromeos/components/tether/message_transfer_operation_unittest.cc
index 5db05a3..ab397356 100644
--- a/chromeos/components/tether/message_transfer_operation_unittest.cc
+++ b/chromeos/components/tether/message_transfer_operation_unittest.cc
@@ -4,8 +4,10 @@
 
 #include "chromeos/components/tether/message_transfer_operation.h"
 
+#include "base/timer/mock_timer.h"
 #include "chromeos/components/tether/fake_ble_connection_manager.h"
 #include "chromeos/components/tether/message_wrapper.h"
+#include "chromeos/components/tether/timer_factory.h"
 #include "components/cryptauth/remote_device_test_util.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -20,6 +22,8 @@
 // except that it must be consistent throughout the test.
 const MessageType kTestMessageType = MessageType::TETHER_AVAILABILITY_REQUEST;
 
+const uint32_t kTestResponseTimeoutSeconds = 5;
+
 // A test double for MessageTransferOperation is needed because
 // MessageTransferOperation has pure virtual methods which must be overridden in
 // order to create a concrete instantiation of the class.
@@ -27,9 +31,7 @@
  public:
   TestOperation(const std::vector<cryptauth::RemoteDevice>& devices_to_connect,
                 BleConnectionManager* connection_manager)
-      : MessageTransferOperation(devices_to_connect, connection_manager),
-        has_operation_started_(false),
-        has_operation_finished_(false) {}
+      : MessageTransferOperation(devices_to_connect, connection_manager) {}
   ~TestOperation() override {}
 
   bool HasDeviceAuthenticated(const cryptauth::RemoteDevice& remote_device) {
@@ -62,6 +64,9 @@
       const cryptauth::RemoteDevice& remote_device) override {
     device_map_[remote_device].received_messages.push_back(
         std::move(message_wrapper));
+
+    if (should_unregister_device_on_message_received_)
+      UnregisterDevice(remote_device);
   }
 
   void OnOperationStarted() override { has_operation_started_ = true; }
@@ -72,6 +77,26 @@
     return kTestMessageType;
   }
 
+  bool ShouldWaitForResponse() override { return should_wait_for_response_; }
+
+  uint32_t GetResponseTimeoutSeconds() override {
+    return response_timeout_seconds_;
+  }
+
+  void set_should_wait_for_response(bool should_wait_for_response) {
+    should_wait_for_response_ = should_wait_for_response;
+  }
+
+  void set_response_timeout_seconds(uint32_t response_timeout_seconds) {
+    response_timeout_seconds_ = response_timeout_seconds;
+  }
+
+  void set_should_unregister_device_on_message_received(
+      bool should_unregister_device_on_message_received) {
+    should_unregister_device_on_message_received_ =
+        should_unregister_device_on_message_received;
+  }
+
   bool has_operation_started() { return has_operation_started_; }
 
   bool has_operation_finished() { return has_operation_finished_; }
@@ -87,8 +112,38 @@
 
   std::map<cryptauth::RemoteDevice, DeviceMapValue> device_map_;
 
-  bool has_operation_started_;
-  bool has_operation_finished_;
+  bool should_wait_for_response_ = true;
+  uint32_t response_timeout_seconds_ = kTestResponseTimeoutSeconds;
+  bool should_unregister_device_on_message_received_ = false;
+  bool has_operation_started_ = false;
+  bool has_operation_finished_ = false;
+};
+
+class TestTimerFactory : public TimerFactory {
+ public:
+  ~TestTimerFactory() override {}
+
+  // TimerFactory:
+  std::unique_ptr<base::Timer> CreateOneShotTimer() override {
+    EXPECT_FALSE(device_id_for_next_timer_.empty());
+    base::MockTimer* mock_timer = new base::MockTimer(
+        false /* retain_user_task */, false /* is_repeating */);
+    device_id_to_timer_map_[device_id_for_next_timer_] = mock_timer;
+    return base::WrapUnique(mock_timer);
+  }
+
+  base::MockTimer* GetResponseTimerForDeviceId(const std::string& device_id) {
+    return device_id_to_timer_map_[device_id_for_next_timer_];
+  }
+
+  void set_device_id_for_next_timer(
+      const std::string& device_id_for_next_timer) {
+    device_id_for_next_timer_ = device_id_for_next_timer;
+  }
+
+ private:
+  std::string device_id_for_next_timer_;
+  std::unordered_map<std::string, base::MockTimer*> device_id_to_timer_map_;
 };
 
 DeviceStatus CreateFakeDeviceStatus() {
@@ -131,8 +186,10 @@
   }
 
   void ConstructOperation(std::vector<cryptauth::RemoteDevice> remote_devices) {
+    test_timer_factory_ = new TestTimerFactory();
     operation_ = base::WrapUnique(
         new TestOperation(remote_devices, fake_ble_connection_manager_.get()));
+    operation_->SetTimerFactoryForTest(base::WrapUnique(test_timer_factory_));
     VerifyOperationStartedAndFinished(false /* has_started */,
                                       false /* has_finished */);
   }
@@ -157,9 +214,43 @@
     EXPECT_EQ(has_finished, operation_->has_operation_finished());
   }
 
+  void TransitionDeviceStatusFromDisconnectedToAuthenticated(
+      const cryptauth::RemoteDevice& remote_device) {
+    test_timer_factory_->set_device_id_for_next_timer(
+        remote_device.GetDeviceId());
+
+    fake_ble_connection_manager_->SetDeviceStatus(
+        remote_device, cryptauth::SecureChannel::Status::CONNECTING);
+    fake_ble_connection_manager_->SetDeviceStatus(
+        remote_device, cryptauth::SecureChannel::Status::CONNECTED);
+    fake_ble_connection_manager_->SetDeviceStatus(
+        remote_device, cryptauth::SecureChannel::Status::AUTHENTICATING);
+    fake_ble_connection_manager_->SetDeviceStatus(
+        remote_device, cryptauth::SecureChannel::Status::AUTHENTICATED);
+  }
+
+  base::MockTimer* GetResponseTimerForDevice(
+      const cryptauth::RemoteDevice& remote_device) {
+    return test_timer_factory_->GetResponseTimerForDeviceId(
+        remote_device.GetDeviceId());
+  }
+
+  void VerifyDefaultTimerCreatedForDevice(
+      const cryptauth::RemoteDevice& remote_device) {
+    VerifyTimerCreatedForDevice(remote_device, kTestResponseTimeoutSeconds);
+  }
+
+  void VerifyTimerCreatedForDevice(const cryptauth::RemoteDevice& remote_device,
+                                   uint32_t response_timeout_seconds) {
+    EXPECT_TRUE(GetResponseTimerForDevice(remote_device));
+    EXPECT_EQ(base::TimeDelta::FromSeconds(response_timeout_seconds),
+              GetResponseTimerForDevice(remote_device)->GetCurrentDelay());
+  }
+
   const std::vector<cryptauth::RemoteDevice> test_devices_;
 
   std::unique_ptr<FakeBleConnectionManager> fake_ble_connection_manager_;
+  TestTimerFactory* test_timer_factory_;
   std::unique_ptr<TestOperation> operation_;
 
  private:
@@ -236,16 +327,10 @@
   EXPECT_TRUE(IsDeviceRegistered(test_devices_[0]));
 
   // Try again and succeed.
-  fake_ble_connection_manager_->SetDeviceStatus(
-      test_devices_[0], cryptauth::SecureChannel::Status::CONNECTING);
-  fake_ble_connection_manager_->SetDeviceStatus(
-      test_devices_[0], cryptauth::SecureChannel::Status::CONNECTED);
-  fake_ble_connection_manager_->SetDeviceStatus(
-      test_devices_[0], cryptauth::SecureChannel::Status::AUTHENTICATING);
-  fake_ble_connection_manager_->SetDeviceStatus(
-      test_devices_[0], cryptauth::SecureChannel::Status::AUTHENTICATED);
+  TransitionDeviceStatusFromDisconnectedToAuthenticated(test_devices_[0]);
   EXPECT_TRUE(IsDeviceRegistered(test_devices_[0]));
   EXPECT_TRUE(operation_->HasDeviceAuthenticated(test_devices_[0]));
+  VerifyDefaultTimerCreatedForDevice(test_devices_[0]);
 
   EXPECT_TRUE(operation_->GetReceivedMessages(test_devices_[0]).empty());
 }
@@ -256,16 +341,14 @@
   InitializeOperation();
   EXPECT_TRUE(IsDeviceRegistered(test_devices_[0]));
 
-  fake_ble_connection_manager_->SetDeviceStatus(
-      test_devices_[0], cryptauth::SecureChannel::Status::CONNECTING);
-  fake_ble_connection_manager_->SetDeviceStatus(
-      test_devices_[0], cryptauth::SecureChannel::Status::CONNECTED);
-  fake_ble_connection_manager_->SetDeviceStatus(
-      test_devices_[0], cryptauth::SecureChannel::Status::AUTHENTICATING);
-  fake_ble_connection_manager_->SetDeviceStatus(
-      test_devices_[0], cryptauth::SecureChannel::Status::AUTHENTICATED);
+  // Simulate how subclasses behave after a successful response: unregister the
+  // device.
+  operation_->set_should_unregister_device_on_message_received(true);
+
+  TransitionDeviceStatusFromDisconnectedToAuthenticated(test_devices_[0]);
   EXPECT_TRUE(IsDeviceRegistered(test_devices_[0]));
   EXPECT_TRUE(operation_->HasDeviceAuthenticated(test_devices_[0]));
+  VerifyDefaultTimerCreatedForDevice(test_devices_[0]);
 
   fake_ble_connection_manager_->ReceiveMessage(
       test_devices_[0],
@@ -280,6 +363,82 @@
             message->GetProto()->SerializeAsString());
 }
 
+TEST_F(MessageTransferOperationTest,
+       TestSuccessfulConnectionAndReceiveMessage_ResponseTimeoutSeconds) {
+  const uint32_t response_timeout_seconds = 90;
+
+  ConstructOperation(std::vector<cryptauth::RemoteDevice>{test_devices_[0]});
+  InitializeOperation();
+  EXPECT_TRUE(IsDeviceRegistered(test_devices_[0]));
+
+  operation_->set_response_timeout_seconds(response_timeout_seconds);
+
+  TransitionDeviceStatusFromDisconnectedToAuthenticated(test_devices_[0]);
+  EXPECT_TRUE(IsDeviceRegistered(test_devices_[0]));
+  EXPECT_TRUE(operation_->HasDeviceAuthenticated(test_devices_[0]));
+  VerifyTimerCreatedForDevice(test_devices_[0], response_timeout_seconds);
+
+  EXPECT_EQ(base::TimeDelta::FromSeconds(response_timeout_seconds),
+            GetResponseTimerForDevice(test_devices_[0])->GetCurrentDelay());
+
+  fake_ble_connection_manager_->ReceiveMessage(
+      test_devices_[0],
+      MessageWrapper(CreateTetherAvailabilityResponse()).ToRawMessage());
+
+  EXPECT_EQ(1u, operation_->GetReceivedMessages(test_devices_[0]).size());
+  std::shared_ptr<MessageWrapper> message =
+      operation_->GetReceivedMessages(test_devices_[0])[0];
+  EXPECT_EQ(MessageType::TETHER_AVAILABILITY_RESPONSE,
+            message->GetMessageType());
+  EXPECT_EQ(CreateTetherAvailabilityResponse().SerializeAsString(),
+            message->GetProto()->SerializeAsString());
+}
+
+TEST_F(MessageTransferOperationTest,
+       TestSuccessfulConnectionAndReceiveMessage_ShouldNotWaitForResponse) {
+  ConstructOperation(std::vector<cryptauth::RemoteDevice>{test_devices_[0]});
+  InitializeOperation();
+  EXPECT_TRUE(IsDeviceRegistered(test_devices_[0]));
+
+  operation_->set_should_wait_for_response(false);
+
+  TransitionDeviceStatusFromDisconnectedToAuthenticated(test_devices_[0]);
+  EXPECT_TRUE(IsDeviceRegistered(test_devices_[0]));
+  EXPECT_TRUE(operation_->HasDeviceAuthenticated(test_devices_[0]));
+
+  // A Timer should not have been created because the operation should not wait
+  // for a response.
+  EXPECT_FALSE(GetResponseTimerForDevice(test_devices_[0]));
+
+  fake_ble_connection_manager_->ReceiveMessage(
+      test_devices_[0],
+      MessageWrapper(CreateTetherAvailabilityResponse()).ToRawMessage());
+
+  EXPECT_EQ(1u, operation_->GetReceivedMessages(test_devices_[0]).size());
+  std::shared_ptr<MessageWrapper> message =
+      operation_->GetReceivedMessages(test_devices_[0])[0];
+  EXPECT_EQ(MessageType::TETHER_AVAILABILITY_RESPONSE,
+            message->GetMessageType());
+  EXPECT_EQ(CreateTetherAvailabilityResponse().SerializeAsString(),
+            message->GetProto()->SerializeAsString());
+}
+
+TEST_F(MessageTransferOperationTest, TestAuthenticatesButTimesOut) {
+  ConstructOperation(std::vector<cryptauth::RemoteDevice>{test_devices_[0]});
+  InitializeOperation();
+  EXPECT_TRUE(IsDeviceRegistered(test_devices_[0]));
+
+  TransitionDeviceStatusFromDisconnectedToAuthenticated(test_devices_[0]);
+  EXPECT_TRUE(IsDeviceRegistered(test_devices_[0]));
+  EXPECT_TRUE(operation_->HasDeviceAuthenticated(test_devices_[0]));
+  VerifyDefaultTimerCreatedForDevice(test_devices_[0]);
+
+  GetResponseTimerForDevice(test_devices_[0])->Fire();
+
+  EXPECT_FALSE(IsDeviceRegistered(test_devices_[0]));
+  EXPECT_TRUE(operation_->has_operation_finished());
+}
+
 TEST_F(MessageTransferOperationTest, TestRepeatedInputDevice) {
   // Construct with two copies of the same device.
   ConstructOperation(
@@ -287,16 +446,10 @@
   InitializeOperation();
   EXPECT_TRUE(IsDeviceRegistered(test_devices_[0]));
 
-  fake_ble_connection_manager_->SetDeviceStatus(
-      test_devices_[0], cryptauth::SecureChannel::Status::CONNECTING);
-  fake_ble_connection_manager_->SetDeviceStatus(
-      test_devices_[0], cryptauth::SecureChannel::Status::CONNECTED);
-  fake_ble_connection_manager_->SetDeviceStatus(
-      test_devices_[0], cryptauth::SecureChannel::Status::AUTHENTICATING);
-  fake_ble_connection_manager_->SetDeviceStatus(
-      test_devices_[0], cryptauth::SecureChannel::Status::AUTHENTICATED);
+  TransitionDeviceStatusFromDisconnectedToAuthenticated(test_devices_[0]);
   EXPECT_TRUE(IsDeviceRegistered(test_devices_[0]));
   EXPECT_TRUE(operation_->HasDeviceAuthenticated(test_devices_[0]));
+  VerifyDefaultTimerCreatedForDevice(test_devices_[0]);
 
   fake_ble_connection_manager_->ReceiveMessage(
       test_devices_[0],
@@ -323,14 +476,7 @@
   // should not be affected.
   fake_ble_connection_manager_->RegisterRemoteDevice(
       test_devices_[1], MessageType::CONNECT_TETHERING_REQUEST);
-  fake_ble_connection_manager_->SetDeviceStatus(
-      test_devices_[1], cryptauth::SecureChannel::Status::CONNECTING);
-  fake_ble_connection_manager_->SetDeviceStatus(
-      test_devices_[1], cryptauth::SecureChannel::Status::CONNECTED);
-  fake_ble_connection_manager_->SetDeviceStatus(
-      test_devices_[1], cryptauth::SecureChannel::Status::AUTHENTICATING);
-  fake_ble_connection_manager_->SetDeviceStatus(
-      test_devices_[1], cryptauth::SecureChannel::Status::AUTHENTICATED);
+  TransitionDeviceStatusFromDisconnectedToAuthenticated(test_devices_[1]);
   EXPECT_TRUE(IsDeviceRegistered(test_devices_[0]));
   EXPECT_FALSE(IsDeviceRegistered(test_devices_[1]));
   EXPECT_FALSE(operation_->HasDeviceAuthenticated(test_devices_[0]));
@@ -353,19 +499,13 @@
   // initialization.
   fake_ble_connection_manager_->RegisterRemoteDevice(
       test_devices_[0], MessageType::CONNECT_TETHERING_REQUEST);
-  fake_ble_connection_manager_->SetDeviceStatus(
-      test_devices_[0], cryptauth::SecureChannel::Status::CONNECTING);
-  fake_ble_connection_manager_->SetDeviceStatus(
-      test_devices_[0], cryptauth::SecureChannel::Status::CONNECTED);
-  fake_ble_connection_manager_->SetDeviceStatus(
-      test_devices_[0], cryptauth::SecureChannel::Status::AUTHENTICATING);
-  fake_ble_connection_manager_->SetDeviceStatus(
-      test_devices_[0], cryptauth::SecureChannel::Status::AUTHENTICATED);
+  TransitionDeviceStatusFromDisconnectedToAuthenticated(test_devices_[0]);
 
   // Now initialize; the authentication handler should have been invoked.
   InitializeOperation();
   EXPECT_TRUE(IsDeviceRegistered(test_devices_[0]));
   EXPECT_TRUE(operation_->HasDeviceAuthenticated(test_devices_[0]));
+  VerifyDefaultTimerCreatedForDevice(test_devices_[0]);
 
   // Receiving a message should work at this point.
   fake_ble_connection_manager_->ReceiveMessage(
@@ -381,6 +521,28 @@
             message->GetProto()->SerializeAsString());
 }
 
+TEST_F(MessageTransferOperationTest,
+       AlreadyAuthenticatedBeforeInitialization_TimesOutWaitingForResponse) {
+  ConstructOperation(std::vector<cryptauth::RemoteDevice>{test_devices_[0]});
+
+  // Simulate the authentication of |test_devices_[0]|'s channel before
+  // initialization.
+  fake_ble_connection_manager_->RegisterRemoteDevice(
+      test_devices_[0], MessageType::CONNECT_TETHERING_REQUEST);
+  TransitionDeviceStatusFromDisconnectedToAuthenticated(test_devices_[0]);
+
+  // Now initialize; the authentication handler should have been invoked.
+  InitializeOperation();
+  EXPECT_TRUE(IsDeviceRegistered(test_devices_[0]));
+  EXPECT_TRUE(operation_->HasDeviceAuthenticated(test_devices_[0]));
+  VerifyDefaultTimerCreatedForDevice(test_devices_[0]);
+
+  GetResponseTimerForDevice(test_devices_[0])->Fire();
+
+  EXPECT_FALSE(IsDeviceRegistered(test_devices_[0]));
+  EXPECT_TRUE(operation_->has_operation_finished());
+}
+
 TEST_F(MessageTransferOperationTest, MultipleDevices) {
   ConstructOperation(test_devices_);
   InitializeOperation();
@@ -392,18 +554,14 @@
   // Authenticate |test_devices_[0]|'s channel.
   fake_ble_connection_manager_->RegisterRemoteDevice(
       test_devices_[0], MessageType::CONNECT_TETHERING_REQUEST);
-  fake_ble_connection_manager_->SetDeviceStatus(
-      test_devices_[0], cryptauth::SecureChannel::Status::CONNECTING);
-  fake_ble_connection_manager_->SetDeviceStatus(
-      test_devices_[0], cryptauth::SecureChannel::Status::CONNECTED);
-  fake_ble_connection_manager_->SetDeviceStatus(
-      test_devices_[0], cryptauth::SecureChannel::Status::AUTHENTICATING);
-  fake_ble_connection_manager_->SetDeviceStatus(
-      test_devices_[0], cryptauth::SecureChannel::Status::AUTHENTICATED);
+  TransitionDeviceStatusFromDisconnectedToAuthenticated(test_devices_[0]);
   EXPECT_TRUE(operation_->HasDeviceAuthenticated(test_devices_[0]));
   EXPECT_TRUE(IsDeviceRegistered(test_devices_[0]));
+  VerifyDefaultTimerCreatedForDevice(test_devices_[0]);
 
   // Fail 3 times to connect to |test_devices_[1]|.
+  test_timer_factory_->set_device_id_for_next_timer(
+      test_devices_[1].GetDeviceId());
   fake_ble_connection_manager_->SetDeviceStatus(
       test_devices_[1], cryptauth::SecureChannel::Status::CONNECTING);
   fake_ble_connection_manager_->SetDeviceStatus(
@@ -418,22 +576,19 @@
       test_devices_[1], cryptauth::SecureChannel::Status::DISCONNECTED);
   EXPECT_FALSE(operation_->HasDeviceAuthenticated(test_devices_[1]));
   EXPECT_FALSE(IsDeviceRegistered(test_devices_[1]));
+  EXPECT_FALSE(GetResponseTimerForDevice(test_devices_[1]));
 
   // Authenticate |test_devices_[2]|'s channel.
   fake_ble_connection_manager_->RegisterRemoteDevice(
       test_devices_[2], MessageType::CONNECT_TETHERING_REQUEST);
-  fake_ble_connection_manager_->SetDeviceStatus(
-      test_devices_[2], cryptauth::SecureChannel::Status::CONNECTING);
-  fake_ble_connection_manager_->SetDeviceStatus(
-      test_devices_[2], cryptauth::SecureChannel::Status::CONNECTED);
-  fake_ble_connection_manager_->SetDeviceStatus(
-      test_devices_[2], cryptauth::SecureChannel::Status::AUTHENTICATING);
-  fake_ble_connection_manager_->SetDeviceStatus(
-      test_devices_[2], cryptauth::SecureChannel::Status::AUTHENTICATED);
+  TransitionDeviceStatusFromDisconnectedToAuthenticated(test_devices_[2]);
   EXPECT_TRUE(operation_->HasDeviceAuthenticated(test_devices_[2]));
   EXPECT_TRUE(IsDeviceRegistered(test_devices_[2]));
+  VerifyDefaultTimerCreatedForDevice(test_devices_[2]);
 
   // Fail to authenticate |test_devices_[3]|'s channel.
+  test_timer_factory_->set_device_id_for_next_timer(
+      test_devices_[3].GetDeviceId());
   fake_ble_connection_manager_->RegisterRemoteDevice(
       test_devices_[3], MessageType::CONNECT_TETHERING_REQUEST);
   fake_ble_connection_manager_->SetDeviceStatus(
@@ -446,6 +601,7 @@
       test_devices_[3], cryptauth::SecureChannel::Status::DISCONNECTED);
   EXPECT_FALSE(operation_->HasDeviceAuthenticated(test_devices_[3]));
   EXPECT_FALSE(IsDeviceRegistered(test_devices_[3]));
+  EXPECT_FALSE(GetResponseTimerForDevice(test_devices_[3]));
 }
 
 }  // namespace tether
diff --git a/chromeos/components/tether/message_wrapper.cc b/chromeos/components/tether/message_wrapper.cc
index 9a167010..a4f1248 100644
--- a/chromeos/components/tether/message_wrapper.cc
+++ b/chromeos/components/tether/message_wrapper.cc
@@ -47,6 +47,12 @@
       keep_alive_tickle->ParseFromString(decoded_message);
       return std::move(keep_alive_tickle);
     }
+    case MessageType::KEEP_ALIVE_TICKLE_RESPONSE: {
+      std::unique_ptr<KeepAliveTickleResponse> keep_alive_tickle_response =
+          base::MakeUnique<KeepAliveTickleResponse>();
+      keep_alive_tickle_response->ParseFromString(decoded_message);
+      return std::move(keep_alive_tickle_response);
+    }
     case MessageType::TETHER_AVAILABILITY_REQUEST: {
       std::unique_ptr<TetherAvailabilityRequest> tether_request =
           base::MakeUnique<TetherAvailabilityRequest>();
@@ -123,6 +129,10 @@
     : type_(MessageType::KEEP_ALIVE_TICKLE),
       proto_(new KeepAliveTickle(tickle)) {}
 
+MessageWrapper::MessageWrapper(const KeepAliveTickleResponse& response)
+    : type_(MessageType::KEEP_ALIVE_TICKLE_RESPONSE),
+      proto_(new KeepAliveTickleResponse(response)) {}
+
 MessageWrapper::MessageWrapper(const TetherAvailabilityRequest& request)
     : type_(MessageType::TETHER_AVAILABILITY_REQUEST),
       proto_(new TetherAvailabilityRequest(request)) {}
diff --git a/chromeos/components/tether/message_wrapper.h b/chromeos/components/tether/message_wrapper.h
index d62ac5f..9d92dbc1 100644
--- a/chromeos/components/tether/message_wrapper.h
+++ b/chromeos/components/tether/message_wrapper.h
@@ -31,6 +31,7 @@
   MessageWrapper(const ConnectTetheringResponse& response);
   MessageWrapper(const DisconnectTetheringRequest& request);
   MessageWrapper(const KeepAliveTickle& tickle);
+  MessageWrapper(const KeepAliveTickleResponse& response);
   MessageWrapper(const TetherAvailabilityRequest& request);
   MessageWrapper(const TetherAvailabilityResponse& response);
 
diff --git a/chromeos/components/tether/message_wrapper_unittest.cc b/chromeos/components/tether/message_wrapper_unittest.cc
index 9e5ea88..78a7e24 100644
--- a/chromeos/components/tether/message_wrapper_unittest.cc
+++ b/chromeos/components/tether/message_wrapper_unittest.cc
@@ -103,6 +103,14 @@
   VerifyProtoConversion(&tickle, wrapper, MessageType::KEEP_ALIVE_TICKLE);
 }
 
+TEST_F(MessageWrapperTest, TestToAndFromRawMessage_KeepAliveTickleResponse) {
+  KeepAliveTickleResponse response;
+
+  MessageWrapper wrapper(response);
+  VerifyProtoConversion(&response, wrapper,
+                        MessageType::KEEP_ALIVE_TICKLE_RESPONSE);
+}
+
 TEST_F(MessageWrapperTest, TestToAndFromRawMessage_TetherAvailabilityRequest) {
   TetherAvailabilityRequest request;
 
diff --git a/chromeos/components/tether/proto/tether.proto b/chromeos/components/tether/proto/tether.proto
index a0b7ddf..634429c 100644
--- a/chromeos/components/tether/proto/tether.proto
+++ b/chromeos/components/tether/proto/tether.proto
@@ -19,6 +19,7 @@
   CONNECT_TETHERING_RESPONSE = 4;
   DISCONNECT_TETHERING_REQUEST = 5;
   KEEP_ALIVE_TICKLE = 6;
+  KEEP_ALIVE_TICKLE_RESPONSE = 7;
 }
 
 // Meant to communicate the host's current Wifi status. This is intended to
@@ -103,5 +104,10 @@
 // Next id: 1
 message KeepAliveTickle {}
 
+// Next id: 2
+message KeepAliveTickleResponse {
+  optional DeviceStatus device_status = 1;
+}
+
 // Next id: 1
 message DisconnectTetheringRequest {}
diff --git a/components/autofill/android/BUILD.gn b/components/autofill/android/BUILD.gn
index dab9ec2..b722fe53 100644
--- a/components/autofill/android/BUILD.gn
+++ b/components/autofill/android/BUILD.gn
@@ -13,6 +13,7 @@
   deps = [
     ":autofill_java_resources",
     "//base:base_java",
+    "//content/public/android:content_java",
     "//third_party/android_tools:android_support_v7_appcompat_java",
     "//ui/android:ui_java",
   ]
@@ -20,6 +21,34 @@
     "java/src/org/chromium/components/autofill/AutofillDelegate.java",
     "java/src/org/chromium/components/autofill/AutofillKeyboardAccessory.java",
     "java/src/org/chromium/components/autofill/AutofillPopup.java",
+    "java/src/org/chromium/components/autofill/AutofillProvider.java",
     "java/src/org/chromium/components/autofill/AutofillSuggestion.java",
+    "java/src/org/chromium/components/autofill/FormData.java",
+    "java/src/org/chromium/components/autofill/FormFieldData.java",
+  ]
+}
+
+generate_jni("jni_headers") {
+  sources = [
+    "java/src/org/chromium/components/autofill/AutofillProvider.java",
+    "java/src/org/chromium/components/autofill/FormData.java",
+    "java/src/org/chromium/components/autofill/FormFieldData.java",
+  ]
+  jni_package = "autofill"
+}
+
+static_library("provider") {
+  sources = [
+    "autofill_provider_android.cc",
+    "autofill_provider_android.h",
+    "form_data_android.cc",
+    "form_data_android.h",
+    "form_field_data_android.cc",
+    "form_field_data_android.h",
+  ]
+  deps = [
+    ":jni_headers",
+    "//components/autofill/core/browser:browser",
+    "//content/public/browser",
   ]
 }
diff --git a/components/autofill/android/DEPS b/components/autofill/android/DEPS
new file mode 100644
index 0000000..042235b
--- /dev/null
+++ b/components/autofill/android/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+  "+content/public/android/java",
+  "+content/public/browser",
+]
diff --git a/components/autofill/android/autofill_provider_android.cc b/components/autofill/android/autofill_provider_android.cc
new file mode 100644
index 0000000..9dbe9570
--- /dev/null
+++ b/components/autofill/android/autofill_provider_android.cc
@@ -0,0 +1,196 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/android/autofill_provider_android.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/memory/ptr_util.h"
+#include "components/autofill/android/form_data_android.h"
+#include "components/autofill/core/browser/autofill_handler_proxy.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/web_contents.h"
+#include "jni/AutofillProvider_jni.h"
+#include "ui/gfx/geometry/rect_f.h"
+
+using base::android::AttachCurrentThread;
+using base::android::ConvertUTF16ToJavaString;
+using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaRef;
+using base::android::ScopedJavaLocalRef;
+using content::BrowserThread;
+using content::WebContents;
+using gfx::RectF;
+
+namespace autofill {
+
+const int kInvalidRequestId = -1;
+
+AutofillProviderAndroid::AutofillProviderAndroid(
+    const JavaRef<jobject>& jcaller,
+    content::WebContents* web_contents)
+    : id_(kInvalidRequestId), web_contents_(web_contents) {
+  JNIEnv* env = AttachCurrentThread();
+  java_ref_ = JavaObjectWeakGlobalRef(env, jcaller);
+  Java_AutofillProvider_setNativeAutofillProvider(
+      env, jcaller, reinterpret_cast<jlong>(this));
+}
+
+AutofillProviderAndroid::~AutofillProviderAndroid() {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+  if (obj.is_null())
+    return;
+
+  // Remove the reference to this object on the Java side.
+  Java_AutofillProvider_setNativeAutofillProvider(env, obj, 0);
+}
+
+void AutofillProviderAndroid::OnQueryFormFieldAutofill(
+    AutofillHandlerProxy* handler,
+    int32_t id,
+    const FormData& form,
+    const FormFieldData& field,
+    const gfx::RectF& bounding_box) {
+  // The id isn't passed to Java side because Android API guarantees the
+  // response is always for current session, so we just use the current id
+  // in response, see OnAutofillAvailable.
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  id_ = id;
+
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+  if (obj.is_null())
+    return;
+
+  form_ = base::MakeUnique<FormDataAndroid>(form);
+
+  size_t index;
+  if (!form_->GetFieldIndex(field, &index))
+    return;
+
+  gfx::Rect client_area = web_contents_->GetContainerBounds();
+  gfx::RectF transformed_bounding =
+      bounding_box + client_area.OffsetFromOrigin();
+
+  ScopedJavaLocalRef<jobject> form_obj = form_->GetJavaPeer();
+  handler_ = handler->GetWeakPtr();
+  Java_AutofillProvider_startAutofillSession(
+      env, obj, form_obj, index, transformed_bounding.x(),
+      transformed_bounding.y(), transformed_bounding.width(),
+      transformed_bounding.height());
+}
+
+void AutofillProviderAndroid::OnAutofillAvailable(JNIEnv* env,
+                                                  jobject jcaller,
+                                                  jobject formData) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  if (handler_) {
+    const FormData& form = form_->GetAutofillValues();
+    SendFormDataToRenderer(handler_.get(), id_, form);
+  }
+}
+
+void AutofillProviderAndroid::OnTextFieldDidChange(
+    AutofillHandlerProxy* handler,
+    const FormData& form,
+    const FormFieldData& field,
+    const base::TimeTicks timestamp) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  if (!ValidateHandler(handler) || !form_->SimilarFormAs(form))
+    return;
+
+  size_t index;
+  if (!form_->GetSimilarFieldIndex(field, &index))
+    return;
+
+  form_->OnTextFieldDidChange(index, field.value);
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+  if (obj.is_null())
+    return;
+
+  Java_AutofillProvider_onTextFieldDidChange(env, obj, index);
+}
+
+bool AutofillProviderAndroid::OnWillSubmitForm(
+    AutofillHandlerProxy* handler,
+    const FormData& form,
+    const base::TimeTicks timestamp) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  if (!ValidateHandler(handler) || !form_->SimilarFormAs(form))
+    return false;
+
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+  if (obj.is_null())
+    return false;
+  Java_AutofillProvider_onWillSubmitForm(env, obj);
+  return true;
+}
+
+void AutofillProviderAndroid::OnFocusNoLongerOnForm(
+    AutofillHandlerProxy* handler) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  if (!ValidateHandler(handler))
+    return;
+
+  OnFocusChanged(false, 0, RectF());
+}
+
+void AutofillProviderAndroid::OnFocusChanged(bool focus_on_form,
+                                             size_t index,
+                                             const gfx::RectF& bounding_box) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+  if (obj.is_null())
+    return;
+
+  Java_AutofillProvider_onFocusChanged(
+      env, obj, focus_on_form, index, bounding_box.x(), bounding_box.y(),
+      bounding_box.width(), bounding_box.height());
+}
+
+void AutofillProviderAndroid::OnDidFillAutofillFormData(
+    AutofillHandlerProxy* handler,
+    const FormData& form,
+    base::TimeTicks timestamp) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  if (handler != handler_.get() || !form_ || !form_->SimilarFormAs(form))
+    return;
+
+  for (const FormFieldData& field : form.fields) {
+    if (!field.is_autofilled)
+      continue;
+    OnTextFieldDidChange(handler, form, field, timestamp);
+  }
+}
+
+void AutofillProviderAndroid::Reset(AutofillHandlerProxy* handler) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  if (handler == handler_.get()) {
+    handler_.reset();
+    JNIEnv* env = AttachCurrentThread();
+    ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+    if (obj.is_null())
+      return;
+
+    Java_AutofillProvider_reset(env, obj);
+  }
+}
+
+bool AutofillProviderAndroid::ValidateHandler(AutofillHandlerProxy* handler) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  bool ret = handler == handler_.get();
+  if (!ret)
+    handler_.reset();
+  return ret;
+}
+
+bool RegisterAutofillProvider(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace autofill
diff --git a/components/autofill/android/autofill_provider_android.h b/components/autofill/android/autofill_provider_android.h
new file mode 100644
index 0000000..b75d546
--- /dev/null
+++ b/components/autofill/android/autofill_provider_android.h
@@ -0,0 +1,70 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_AUTOFILL_ANDROID_AUTOFILL_PROVIDER_ANDROID_H_
+#define COMPONENTS_AUTOFILL_ANDROID_AUTOFILL_PROVIDER_ANDROID_H_
+
+#include "base/android/jni_weak_ref.h"
+#include "base/memory/weak_ptr.h"
+#include "components/autofill/core/browser/autofill_provider.h"
+
+namespace content {
+class WebContents;
+}
+
+namespace autofill {
+
+class FormDataAndroid;
+
+// Android implementation of AutofillProvider, it has one instance per
+// WebContents, this class is native peer of AutofillProvider.java.
+class AutofillProviderAndroid : public AutofillProvider {
+ public:
+  AutofillProviderAndroid(const base::android::JavaRef<jobject>& jcaller,
+                          content::WebContents* web_contents);
+  ~AutofillProviderAndroid() override;
+
+  // AutofillProvider:
+  void OnQueryFormFieldAutofill(AutofillHandlerProxy* handler,
+                                int32_t id,
+                                const FormData& form,
+                                const FormFieldData& field,
+                                const gfx::RectF& bounding_box) override;
+  void OnTextFieldDidChange(AutofillHandlerProxy* handler,
+                            const FormData& form,
+                            const FormFieldData& field,
+                            const base::TimeTicks timestamp) override;
+  bool OnWillSubmitForm(AutofillHandlerProxy* handler,
+                        const FormData& form,
+                        const base::TimeTicks timestamp) override;
+  void OnFocusNoLongerOnForm(AutofillHandlerProxy* handler) override;
+  void OnDidFillAutofillFormData(AutofillHandlerProxy* handler,
+                                 const FormData& form,
+                                 base::TimeTicks timestamp) override;
+  void Reset(AutofillHandlerProxy* handler) override;
+
+  // Methods called by Java.
+  void OnAutofillAvailable(JNIEnv* env, jobject jcaller, jobject form_data);
+
+ private:
+  void OnFocusChanged(bool focus_on_form,
+                      size_t index,
+                      const gfx::RectF& bounding_box);
+
+  bool ValidateHandler(AutofillHandlerProxy* handler);
+
+  int32_t id_;
+  std::unique_ptr<FormDataAndroid> form_;
+  base::WeakPtr<AutofillHandlerProxy> handler_;
+  JavaObjectWeakGlobalRef java_ref_;
+  content::WebContents* web_contents_;
+
+  DISALLOW_COPY_AND_ASSIGN(AutofillProviderAndroid);
+};
+
+bool RegisterAutofillProvider(JNIEnv* env);
+
+}  // namespace autofill
+
+#endif  // COMPONENTS_AUTOFILL_ANDROID_AUTOFILL_PROVIDER_ANDROID_H_
diff --git a/components/autofill/android/form_data_android.cc b/components/autofill/android/form_data_android.cc
new file mode 100644
index 0000000..8a8af68
--- /dev/null
+++ b/components/autofill/android/form_data_android.cc
@@ -0,0 +1,102 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/android/form_data_android.h"
+
+#include "base/android/jni_string.h"
+#include "components/autofill/android/form_field_data_android.h"
+#include "jni/FormData_jni.h"
+
+using base::android::AttachCurrentThread;
+using base::android::ConvertJavaStringToUTF16;
+using base::android::ConvertUTF16ToJavaString;
+using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
+using base::android::ScopedJavaGlobalRef;
+using base::android::ScopedJavaLocalRef;
+
+namespace autofill {
+
+FormDataAndroid::FormDataAndroid(const FormData& form)
+    : form_(form), index_(0) {}
+
+FormDataAndroid::~FormDataAndroid() {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+  if (obj.is_null())
+    return;
+
+  Java_FormData_onNativeDestroyed(env, obj);
+}
+
+ScopedJavaLocalRef<jobject> FormDataAndroid::GetJavaPeer() {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+  if (obj.is_null()) {
+    for (size_t i = 0; i < form_.fields.size(); ++i) {
+      fields_.push_back(std::unique_ptr<FormFieldDataAndroid>(
+          new FormFieldDataAndroid(&form_.fields[i])));
+    }
+    ScopedJavaLocalRef<jstring> jname =
+        ConvertUTF16ToJavaString(env, form_.name);
+    ScopedJavaLocalRef<jstring> jhost =
+        ConvertUTF8ToJavaString(env, form_.origin.host());
+    obj = Java_FormData_createFormData(env, reinterpret_cast<intptr_t>(this),
+                                       jname, jhost, form_.fields.size());
+    java_ref_ = JavaObjectWeakGlobalRef(env, obj);
+  }
+  return obj;
+}
+
+const FormData& FormDataAndroid::GetAutofillValues() {
+  for (std::unique_ptr<FormFieldDataAndroid>& field : fields_)
+    field->GetValue();
+  return form_;
+}
+
+ScopedJavaLocalRef<jobject> FormDataAndroid::GetNextFormFieldData(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& jcaller) {
+  DCHECK(index_ <= fields_.size());
+  if (index_ == fields_.size())
+    return ScopedJavaLocalRef<jobject>();
+  return fields_[index_++]->GetJavaPeer();
+}
+
+void FormDataAndroid::OnTextFieldDidChange(size_t index,
+                                           const base::string16& value) {
+  form_.fields[index].value = value;
+  fields_[index]->OnTextFieldDidChange(value);
+}
+
+bool FormDataAndroid::GetFieldIndex(const FormFieldData& field, size_t* index) {
+  for (size_t i = 0; i < form_.fields.size(); ++i) {
+    if (form_.fields[i].SameFieldAs(field)) {
+      *index = i;
+      return true;
+    }
+  }
+  return false;
+}
+
+bool FormDataAndroid::GetSimilarFieldIndex(const FormFieldData& field,
+                                           size_t* index) {
+  for (size_t i = 0; i < form_.fields.size(); ++i) {
+    if (form_.fields[i].SimilarFieldAs(field)) {
+      *index = i;
+      return true;
+    }
+  }
+  return false;
+}
+
+bool FormDataAndroid::SimilarFormAs(const FormData& form) {
+  return form_.SimilarFormAs(form);
+}
+
+bool RegisterFormDataAndroid(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace autofill
diff --git a/components/autofill/android/form_data_android.h b/components/autofill/android/form_data_android.h
new file mode 100644
index 0000000..130995a
--- /dev/null
+++ b/components/autofill/android/form_data_android.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 COMPONENTS_AUTOFILL_ANDROID_FORM_DATA_ANDROID_H_
+#define COMPONENTS_AUTOFILL_ANDROID_FORM_DATA_ANDROID_H_
+
+#include "base/android/jni_weak_ref.h"
+#include "base/android/scoped_java_ref.h"
+#include "components/autofill/core/common/form_data.h"
+
+namespace autofill {
+
+class FormFieldDataAndroid;
+
+// This class is native peer of FormData.java, to make autofill::FormData
+// available in Java.
+class FormDataAndroid {
+ public:
+  FormDataAndroid(const FormData& form);
+  virtual ~FormDataAndroid();
+
+  base::android::ScopedJavaLocalRef<jobject> GetJavaPeer();
+
+  // Get autofill values from Java side and return FormData.
+  const FormData& GetAutofillValues();
+
+  base::android::ScopedJavaLocalRef<jobject> GetNextFormFieldData(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& jcaller);
+
+  // Get index of given field, return True and index of focus field if found.
+  bool GetFieldIndex(const FormFieldData& field, size_t* index);
+
+  // Get index of given field, return True and index of focus field if
+  // similar field is found. This method compares less attributes than
+  // GetFieldIndex() does, and should be used when field could be changed
+  // dynamically, but the changed has no impact on autofill purpose, e.g. css
+  // style change, see FormFieldData::SimilarFieldAs() for details.
+  bool GetSimilarFieldIndex(const FormFieldData& field, size_t* index);
+
+  // Return true if this form is similar to the given form.
+  bool SimilarFormAs(const FormData& form);
+
+  // Invoked when form field which specified by |index| is charged to new
+  // |value|.
+  void OnTextFieldDidChange(size_t index, const base::string16& value);
+
+ private:
+  FormData form_;
+  std::vector<std::unique_ptr<FormFieldDataAndroid>> fields_;
+  JavaObjectWeakGlobalRef java_ref_;
+  // keep track of index when popping up fields to Java.
+  size_t index_;
+
+  DISALLOW_COPY_AND_ASSIGN(FormDataAndroid);
+};
+
+bool RegisterFormDataAndroid(JNIEnv* env);
+
+}  // namespace autofill
+
+#endif  // COMPONENTS_AUTOFILL_ANDROID_FORM_DATA_ANDROID_H_
diff --git a/components/autofill/android/form_field_data_android.cc b/components/autofill/android/form_field_data_android.cc
new file mode 100644
index 0000000..15d5163
--- /dev/null
+++ b/components/autofill/android/form_field_data_android.cc
@@ -0,0 +1,76 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/android/form_field_data_android.h"
+
+#include "base/android/jni_string.h"
+#include "jni/FormFieldData_jni.h"
+
+using base::android::AttachCurrentThread;
+using base::android::ConvertJavaStringToUTF16;
+using base::android::ConvertUTF16ToJavaString;
+using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
+using base::android::JavaRef;
+using base::android::ScopedJavaGlobalRef;
+using base::android::ScopedJavaLocalRef;
+
+namespace autofill {
+
+FormFieldDataAndroid::FormFieldDataAndroid(FormFieldData* field)
+    : field_ptr_(field) {}
+
+ScopedJavaLocalRef<jobject> FormFieldDataAndroid::GetJavaPeer() {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+  if (obj.is_null()) {
+    ScopedJavaLocalRef<jstring> jname =
+        ConvertUTF16ToJavaString(env, field_ptr_->name);
+    ScopedJavaLocalRef<jstring> jlabel =
+        ConvertUTF16ToJavaString(env, field_ptr_->label);
+    ScopedJavaLocalRef<jstring> jvalue =
+        ConvertUTF16ToJavaString(env, field_ptr_->value);
+    ScopedJavaLocalRef<jstring> jautocomplete_attr =
+        ConvertUTF8ToJavaString(env, field_ptr_->autocomplete_attribute);
+    ScopedJavaLocalRef<jstring> jplaceholder =
+        ConvertUTF16ToJavaString(env, field_ptr_->placeholder);
+    ScopedJavaLocalRef<jstring> jid =
+        ConvertUTF16ToJavaString(env, field_ptr_->id);
+    ScopedJavaLocalRef<jstring> jtype =
+        ConvertUTF8ToJavaString(env, field_ptr_->form_control_type);
+
+    obj = Java_FormFieldData_createFormFieldData(
+        env, jname, jlabel, jvalue, jautocomplete_attr,
+        field_ptr_->should_autocomplete, jplaceholder, jtype, jid);
+    java_ref_ = JavaObjectWeakGlobalRef(env, obj);
+  }
+  return obj;
+}
+
+void FormFieldDataAndroid::GetValue() {
+  JNIEnv* env = AttachCurrentThread();
+
+  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+  if (obj.is_null())
+    return;
+  ScopedJavaLocalRef<jstring> jvalue = Java_FormFieldData_getValue(env, obj);
+  if (jvalue.is_null())
+    return;
+  field_ptr_->value = ConvertJavaStringToUTF16(env, jvalue);
+  field_ptr_->is_autofilled = true;
+}
+
+void FormFieldDataAndroid::OnTextFieldDidChange(const base::string16& value) {
+  field_ptr_->value = value;
+  field_ptr_->is_autofilled = false;
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+  if (obj.is_null())
+    return;
+
+  Java_FormFieldData_updateValue(env, obj,
+                                 ConvertUTF16ToJavaString(env, value));
+}
+
+}  // namespace autofill
diff --git a/components/autofill/android/form_field_data_android.h b/components/autofill/android/form_field_data_android.h
new file mode 100644
index 0000000..c4fd6a1
--- /dev/null
+++ b/components/autofill/android/form_field_data_android.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 COMPONENTS_AUTOFILL_ANDROID_FORM_FIELD_DATA_ANDROID_H_
+#define COMPONENTS_AUTOFILL_ANDROID_FORM_FIELD_DATA_ANDROID_H_
+
+#include "base/android/jni_weak_ref.h"
+#include "base/android/scoped_java_ref.h"
+#include "components/autofill/core/common/form_field_data.h"
+
+namespace autofill {
+
+// This class is native peer of FormFieldData.java, makes
+// autofill::FormFieldData available in Java.
+class FormFieldDataAndroid {
+ public:
+  FormFieldDataAndroid(FormFieldData* field);
+  virtual ~FormFieldDataAndroid() {}
+
+  base::android::ScopedJavaLocalRef<jobject> GetJavaPeer();
+  void GetValue();
+  void OnTextFieldDidChange(const base::string16& value);
+
+ private:
+  // Not owned.
+  FormFieldData* field_ptr_;
+  JavaObjectWeakGlobalRef java_ref_;
+
+  DISALLOW_COPY_AND_ASSIGN(FormFieldDataAndroid);
+};
+
+}  // namespace autofill
+
+#endif  // COMPONENTS_AUTOFILL_ANDROID_FORM_FIELD_DATA_ANDROID_H_
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
new file mode 100644
index 0000000..ef2569c
--- /dev/null
+++ b/components/autofill/android/java/src/org/chromium/components/autofill/AutofillProvider.java
@@ -0,0 +1,120 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.components.autofill;
+
+import android.util.SparseArray;
+import android.view.ViewGroup;
+import android.view.ViewStructure;
+
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.JNINamespace;
+import org.chromium.content_public.browser.WebContents;
+
+/**
+ * This class defines interface of AutofillProvider, it doesn't use chrome's
+ * autofill service or suggestion UI, instead, uses third party autofill service
+ * by knowing of format structure and user's input.
+ *
+ * AutofillProvider handles one autofill session at time, each call of
+ * queryFormFieldAutofill cancels previous session and starts a new one, the
+ * calling of other methods shall associate with current session.
+ *
+ */
+@JNINamespace("autofill")
+public abstract class AutofillProvider {
+    public AutofillProvider() {}
+
+    /**
+     * Invoked when container view is changed.
+     *
+     * @param containerView new container view.
+     */
+    public abstract void onContainerViewChanged(ViewGroup containerView);
+
+    public abstract void setWebContents(WebContents webContents);
+
+    /**
+     * Invoked when autofill value is available, AutofillProvider shall fill the
+     * form with the provided values.
+     *
+     * @param values the array of autofill values, the key is virtual id of form
+     *            field.
+     */
+    public abstract void autofill(final SparseArray<String> values);
+
+    /**
+     * Invoked when autofill service needs the form structure.
+     *
+     * @param structure see View.onProvideAutofillVirtualStructure()
+     * @param flags see View.onProvideAutofillVirtualStructure()
+     */
+    public abstract void onProvideAutoFillVirtualStructure(ViewStructure structure, int flags);
+
+    /**
+     * Invoked when filling form is need. AutofillProvider shall ask autofill
+     * service for the values with which to fill the form.
+     *
+     * @param formData the form needs to fill.
+     * @param focus the index of focus field in formData
+     * @param x the boundary of focus field.
+     * @param y the boundary of focus field.
+     * @param width the boundary of focus field.
+     * @param height the boundary of focus field.
+     */
+    @CalledByNative
+    protected abstract void startAutofillSession(
+            FormData formData, float focus, float x, float y, float width, float height);
+
+    /**
+     * Invoked when text field is changed.
+     *
+     * @param index index of field in current form.
+     */
+    @CalledByNative
+    protected abstract void onTextFieldDidChange(int index);
+
+    /**
+     * Invoked when current form will be submitted.
+     *
+     */
+    @CalledByNative
+    protected abstract void onWillSubmitForm();
+
+    /**
+     * Invoked when focus field changed.
+     *
+     * @param focusOnForm whether focus is still on form.
+     * @param focusItem the index of field has focus
+     * @param x the boundary of focus field.
+     * @param y the boundary of focus field.
+     * @param width the boundary of focus field.
+     * @param height the boundary of focus field.
+     */
+    @CalledByNative
+    protected abstract void onFocusChanged(
+            boolean focusOnForm, int focusItem, float x, float y, float width, float height);
+
+    /**
+     * Send form to renderer for filling.
+     *
+     * @param nativeAutofillProvider the native autofill provider.
+     * @param formData the form to fill.
+     */
+    protected void autofill(long nativeAutofillProvider, FormData formData) {
+        nativeOnAutofillAvailable(nativeAutofillProvider, formData);
+    }
+
+    /**
+     * Invoked when current query need to be reset.
+     */
+    @CalledByNative
+    protected abstract void reset();
+
+    @CalledByNative
+    protected abstract void setNativeAutofillProvider(long nativeAutofillProvider);
+
+    private native void nativeOnAutofillAvailable(
+            long nativeAutofillProviderAndroid, FormData formData);
+}
diff --git a/components/autofill/android/java/src/org/chromium/components/autofill/FormData.java b/components/autofill/android/java/src/org/chromium/components/autofill/FormData.java
new file mode 100644
index 0000000..ca1362a2
--- /dev/null
+++ b/components/autofill/android/java/src/org/chromium/components/autofill/FormData.java
@@ -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.
+
+package org.chromium.components.autofill;
+
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.JNINamespace;
+
+import java.util.ArrayList;
+
+/**
+ * The wrap class of native autofill::FormDataAndroid.
+ */
+@JNINamespace("autofill")
+public class FormData {
+    public final String mName;
+    public final String mHost;
+    public final ArrayList<FormFieldData> mFields;
+
+    private long mNativeObj;
+
+    @CalledByNative
+    private static FormData createFormData(
+            long nativeObj, String name, String origin, int fieldCount) {
+        return new FormData(nativeObj, name, origin, fieldCount);
+    }
+
+    private FormData(long nativeObj, String name, String host, int fieldCount) {
+        mNativeObj = nativeObj;
+        mName = name;
+        mHost = host;
+        mFields = new ArrayList<FormFieldData>(fieldCount);
+        popupFormFields(fieldCount);
+    }
+
+    private void popupFormFields(int fieldCount) {
+        FormFieldData formFieldData = nativeGetNextFormFieldData(mNativeObj);
+        while (formFieldData != null) {
+            mFields.add(formFieldData);
+            formFieldData = nativeGetNextFormFieldData(mNativeObj);
+        }
+        assert mFields.size() == fieldCount;
+    }
+
+    @CalledByNative
+    private void onNativeDestroyed() {
+        mNativeObj = 0;
+    }
+
+    private native FormFieldData nativeGetNextFormFieldData(long nativeFormDataAndroid);
+}
diff --git a/components/autofill/android/java/src/org/chromium/components/autofill/FormFieldData.java b/components/autofill/android/java/src/org/chromium/components/autofill/FormFieldData.java
new file mode 100644
index 0000000..6657bc1
--- /dev/null
+++ b/components/autofill/android/java/src/org/chromium/components/autofill/FormFieldData.java
@@ -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.
+
+package org.chromium.components.autofill;
+
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.JNINamespace;
+
+/**
+ * The wrap class of native autofill::FormFieldDataAndroid.
+ */
+@JNINamespace("autofill")
+public class FormFieldData {
+    public final String mLabel;
+    public final String mName;
+    public final String mAutocompleteAttr;
+    public final boolean mShouldAutocomplete;
+    public final String mPlaceholder;
+    public final String mType;
+    public final String mId;
+
+    private String mValue;
+
+    private FormFieldData(String name, String label, String value, String autocompleteAttr,
+            boolean shouldAutocomplete, String placeholder, String type, String id) {
+        mName = name;
+        mLabel = label;
+        mValue = value;
+        mAutocompleteAttr = autocompleteAttr;
+        mShouldAutocomplete = shouldAutocomplete;
+        mPlaceholder = placeholder;
+        mType = type;
+        mId = id;
+    }
+
+    /**
+     * @return value of field.
+     */
+    @CalledByNative
+    public String getValue() {
+        return mValue;
+    }
+
+    @CalledByNative
+    public void updateValue(String value) {
+        mValue = value;
+    }
+
+    @CalledByNative
+    private static FormFieldData createFormFieldData(String name, String label, String value,
+            String autocompleteAttr, boolean shouldAutocomplete, String placeholder, String type,
+            String id) {
+        return new FormFieldData(
+                name, label, value, autocompleteAttr, shouldAutocomplete, placeholder, type, id);
+    }
+}
diff --git a/components/autofill/content/browser/content_autofill_driver.cc b/components/autofill/content/browser/content_autofill_driver.cc
index d897ff3cb..4676489 100644
--- a/components/autofill/content/browser/content_autofill_driver.cc
+++ b/components/autofill/content/browser/content_autofill_driver.cc
@@ -10,6 +10,7 @@
 #include "components/autofill/content/browser/content_autofill_driver_factory.h"
 #include "components/autofill/core/browser/autofill_client.h"
 #include "components/autofill/core/browser/autofill_external_delegate.h"
+#include "components/autofill/core/browser/autofill_handler_proxy.h"
 #include "components/autofill/core/browser/autofill_manager.h"
 #include "components/autofill/core/browser/form_structure.h"
 #include "components/autofill/core/common/autofill_switches.h"
@@ -32,16 +33,24 @@
     content::RenderFrameHost* render_frame_host,
     AutofillClient* client,
     const std::string& app_locale,
-    AutofillManager::AutofillDownloadManagerState enable_download_manager)
+    AutofillManager::AutofillDownloadManagerState enable_download_manager,
+    AutofillProvider* provider)
     : render_frame_host_(render_frame_host),
-      autofill_manager_(new AutofillManager(this,
-                                            client,
-                                            app_locale,
-                                            enable_download_manager)),
-      autofill_external_delegate_(autofill_manager_.get(), this),
+      autofill_manager_(nullptr),
       key_press_handler_manager_(this),
       binding_(this) {
-  autofill_manager_->SetExternalDelegate(&autofill_external_delegate_);
+  // AutofillManager isn't used if provider is valid, Autofill provider is
+  // currently used by Android only.
+  if (provider) {
+    autofill_handler_ = base::MakeUnique<AutofillHandlerProxy>(this, provider);
+  } else {
+    autofill_handler_ = base::MakeUnique<AutofillManager>(
+        this, client, app_locale, enable_download_manager);
+    autofill_manager_ = static_cast<AutofillManager*>(autofill_handler_.get());
+    autofill_external_delegate_ =
+        base::MakeUnique<AutofillExternalDelegate>(autofill_manager_, this);
+    autofill_manager_->SetExternalDelegate(autofill_external_delegate_.get());
+  }
 }
 
 ContentAutofillDriver::~ContentAutofillDriver() {}
@@ -148,7 +157,7 @@
 void ContentAutofillDriver::PopupHidden() {
   // If the unmask prompt is showing, keep showing the preview. The preview
   // will be cleared when the prompt closes.
-  if (!autofill_manager_->IsShowingUnmaskPrompt())
+  if (autofill_manager_ && !autofill_manager_->IsShowingUnmaskPrompt())
     RendererShouldClearPreviewedForm();
 }
 
@@ -176,22 +185,22 @@
 
 void ContentAutofillDriver::FormsSeen(const std::vector<FormData>& forms,
                                       base::TimeTicks timestamp) {
-  autofill_manager_->OnFormsSeen(forms, timestamp);
+  autofill_handler_->OnFormsSeen(forms, timestamp);
 }
 
 void ContentAutofillDriver::WillSubmitForm(const FormData& form,
                                            base::TimeTicks timestamp) {
-  autofill_manager_->OnWillSubmitForm(form, timestamp);
+  autofill_handler_->OnWillSubmitForm(form, timestamp);
 }
 
 void ContentAutofillDriver::FormSubmitted(const FormData& form) {
-  autofill_manager_->OnFormSubmitted(form);
+  autofill_handler_->OnFormSubmitted(form);
 }
 
 void ContentAutofillDriver::TextFieldDidChange(const FormData& form,
                                                const FormFieldData& field,
                                                base::TimeTicks timestamp) {
-  autofill_manager_->OnTextFieldDidChange(form, field, timestamp);
+  autofill_handler_->OnTextFieldDidChange(form, field, timestamp);
 }
 
 void ContentAutofillDriver::QueryFormFieldAutofill(
@@ -199,48 +208,50 @@
     const FormData& form,
     const FormFieldData& field,
     const gfx::RectF& bounding_box) {
-  autofill_manager_->OnQueryFormFieldAutofill(id, form, field, bounding_box);
+  autofill_handler_->OnQueryFormFieldAutofill(id, form, field, bounding_box);
 }
 
 void ContentAutofillDriver::HidePopup() {
-  autofill_manager_->OnHidePopup();
+  autofill_handler_->OnHidePopup();
 }
 
 void ContentAutofillDriver::FocusNoLongerOnForm() {
-  autofill_manager_->OnFocusNoLongerOnForm();
+  autofill_handler_->OnFocusNoLongerOnForm();
 }
 
 void ContentAutofillDriver::DidFillAutofillFormData(const FormData& form,
                                                     base::TimeTicks timestamp) {
-  autofill_manager_->OnDidFillAutofillFormData(form, timestamp);
+  autofill_handler_->OnDidFillAutofillFormData(form, timestamp);
 }
 
 void ContentAutofillDriver::DidPreviewAutofillFormData() {
-  autofill_manager_->OnDidPreviewAutofillFormData();
+  autofill_handler_->OnDidPreviewAutofillFormData();
 }
 
 void ContentAutofillDriver::DidEndTextFieldEditing() {
-  autofill_manager_->OnDidEndTextFieldEditing();
+  autofill_handler_->OnDidEndTextFieldEditing();
 }
 
 void ContentAutofillDriver::SetDataList(
     const std::vector<base::string16>& values,
     const std::vector<base::string16>& labels) {
-  autofill_manager_->OnSetDataList(values, labels);
+  autofill_handler_->OnSetDataList(values, labels);
 }
 
 void ContentAutofillDriver::DidNavigateFrame(
     content::NavigationHandle* navigation_handle) {
   if (navigation_handle->IsInMainFrame() &&
       !navigation_handle->IsSameDocument()) {
-    autofill_manager_->Reset();
+    autofill_handler_->Reset();
   }
 }
 
 void ContentAutofillDriver::SetAutofillManager(
     std::unique_ptr<AutofillManager> manager) {
-  autofill_manager_ = std::move(manager);
-  autofill_manager_->SetExternalDelegate(&autofill_external_delegate_);
+  CHECK(autofill_manager_);
+  autofill_handler_ = std::move(manager);
+  autofill_manager_ = static_cast<AutofillManager*>(autofill_handler_.get());
+  autofill_manager_->SetExternalDelegate(autofill_external_delegate_.get());
 }
 
 const mojom::AutofillAgentPtr& ContentAutofillDriver::GetAutofillAgent() {
diff --git a/components/autofill/content/browser/content_autofill_driver.h b/components/autofill/content/browser/content_autofill_driver.h
index f0ddceb..aa3120d 100644
--- a/components/autofill/content/browser/content_autofill_driver.h
+++ b/components/autofill/content/browser/content_autofill_driver.h
@@ -25,6 +25,7 @@
 namespace autofill {
 
 class AutofillClient;
+class AutofillProvider;
 
 // Class that drives autofill flow in the browser process based on
 // communication from the renderer and from the external world. There is one
@@ -37,7 +38,8 @@
       content::RenderFrameHost* render_frame_host,
       AutofillClient* client,
       const std::string& app_locale,
-      AutofillManager::AutofillDownloadManagerState enable_download_manager);
+      AutofillManager::AutofillDownloadManagerState enable_download_manager,
+      AutofillProvider* provider);
   ~ContentAutofillDriver() override;
 
   // Gets the driver for |render_frame_host|.
@@ -94,10 +96,10 @@
   void DidNavigateFrame(content::NavigationHandle* navigation_handle);
 
   AutofillExternalDelegate* autofill_external_delegate() {
-    return &autofill_external_delegate_;
+    return autofill_external_delegate_.get();
   }
 
-  AutofillManager* autofill_manager() { return autofill_manager_.get(); }
+  AutofillManager* autofill_manager() { return autofill_manager_; }
   content::RenderFrameHost* render_frame_host() { return render_frame_host_; }
 
   const mojom::AutofillAgentPtr& GetAutofillAgent();
@@ -123,13 +125,18 @@
   // always be non-NULL and valid for lifetime of |this|.
   content::RenderFrameHost* const render_frame_host_;
 
-  // AutofillManager instance via which this object drives the shared Autofill
+  // AutofillHandler instance via which this object drives the shared Autofill
   // code.
-  std::unique_ptr<AutofillManager> autofill_manager_;
+  std::unique_ptr<AutofillHandler> autofill_handler_;
+
+  // The pointer to autofill_handler_ if it is AutofillManager instance.
+  // TODO: unify autofill_handler_ and autofill_manager_ to a single pointer to
+  // a common root.
+  AutofillManager* autofill_manager_;
 
   // AutofillExternalDelegate instance that this object instantiates in the
   // case where the Autofill native UI is enabled.
-  AutofillExternalDelegate autofill_external_delegate_;
+  std::unique_ptr<AutofillExternalDelegate> autofill_external_delegate_;
 
   KeyPressHandlerManager key_press_handler_manager_;
 
diff --git a/components/autofill/content/browser/content_autofill_driver_factory.cc b/components/autofill/content/browser/content_autofill_driver_factory.cc
index eee03de0..e49ffd8e 100644
--- a/components/autofill/content/browser/content_autofill_driver_factory.cc
+++ b/components/autofill/content/browser/content_autofill_driver_factory.cc
@@ -23,9 +23,10 @@
     content::RenderFrameHost* render_frame_host,
     AutofillClient* client,
     const std::string& app_locale,
-    AutofillManager::AutofillDownloadManagerState enable_download_manager) {
+    AutofillManager::AutofillDownloadManagerState enable_download_manager,
+    AutofillProvider* provider) {
   return base::MakeUnique<ContentAutofillDriver>(
-      render_frame_host, client, app_locale, enable_download_manager);
+      render_frame_host, client, app_locale, enable_download_manager, provider);
 }
 
 }  // namespace
@@ -42,11 +43,21 @@
     AutofillClient* client,
     const std::string& app_locale,
     AutofillManager::AutofillDownloadManagerState enable_download_manager) {
+  CreateForWebContentsAndDelegate(contents, client, app_locale,
+                                  enable_download_manager, nullptr);
+}
+
+void ContentAutofillDriverFactory::CreateForWebContentsAndDelegate(
+    content::WebContents* contents,
+    AutofillClient* client,
+    const std::string& app_locale,
+    AutofillManager::AutofillDownloadManagerState enable_download_manager,
+    AutofillProvider* provider) {
   if (FromWebContents(contents))
     return;
 
   auto new_factory = base::WrapUnique(new ContentAutofillDriverFactory(
-      contents, client, app_locale, enable_download_manager));
+      contents, client, app_locale, enable_download_manager, provider));
   const std::vector<content::RenderFrameHost*> frames =
       contents->GetAllFrames();
   for (content::RenderFrameHost* frame : frames) {
@@ -94,11 +105,13 @@
     content::WebContents* web_contents,
     AutofillClient* client,
     const std::string& app_locale,
-    AutofillManager::AutofillDownloadManagerState enable_download_manager)
+    AutofillManager::AutofillDownloadManagerState enable_download_manager,
+    AutofillProvider* provider)
     : AutofillDriverFactory(client),
       content::WebContentsObserver(web_contents),
       app_locale_(app_locale),
-      enable_download_manager_(enable_download_manager) {}
+      enable_download_manager_(enable_download_manager),
+      provider_(provider) {}
 
 ContentAutofillDriver* ContentAutofillDriverFactory::DriverForFrame(
     content::RenderFrameHost* render_frame_host) {
@@ -112,7 +125,7 @@
     content::RenderFrameHost* render_frame_host) {
   AddForKey(render_frame_host,
             base::Bind(CreateDriver, render_frame_host, client(), app_locale_,
-                       enable_download_manager_));
+                       enable_download_manager_, provider_));
 }
 
 void ContentAutofillDriverFactory::RenderFrameDeleted(
diff --git a/components/autofill/content/browser/content_autofill_driver_factory.h b/components/autofill/content/browser/content_autofill_driver_factory.h
index 4a1156b..e7f0b97 100644
--- a/components/autofill/content/browser/content_autofill_driver_factory.h
+++ b/components/autofill/content/browser/content_autofill_driver_factory.h
@@ -21,6 +21,7 @@
 namespace autofill {
 
 class ContentAutofillDriver;
+class AutofillProvider;
 
 // Manages lifetime of ContentAutofillDriver. One Factory per WebContents
 // creates one Driver per RenderFrame.
@@ -35,6 +36,14 @@
       AutofillClient* client,
       const std::string& app_locale,
       AutofillManager::AutofillDownloadManagerState enable_download_manager);
+
+  static void CreateForWebContentsAndDelegate(
+      content::WebContents* contents,
+      AutofillClient* client,
+      const std::string& app_locale,
+      AutofillManager::AutofillDownloadManagerState enable_download_manager,
+      AutofillProvider* provider);
+
   static ContentAutofillDriverFactory* FromWebContents(
       content::WebContents* contents);
   static void BindAutofillDriver(
@@ -61,10 +70,12 @@
       content::WebContents* web_contents,
       AutofillClient* client,
       const std::string& app_locale,
-      AutofillManager::AutofillDownloadManagerState enable_download_manager);
+      AutofillManager::AutofillDownloadManagerState enable_download_manager,
+      AutofillProvider* provider);
 
   std::string app_locale_;
   AutofillManager::AutofillDownloadManagerState enable_download_manager_;
+  AutofillProvider* provider_;
 };
 
 }  // namespace autofill
diff --git a/components/autofill/content/browser/content_autofill_driver_unittest.cc b/components/autofill/content/browser/content_autofill_driver_unittest.cc
index c18bcbe9b..1be8644 100644
--- a/components/autofill/content/browser/content_autofill_driver_unittest.cc
+++ b/components/autofill/content/browser/content_autofill_driver_unittest.cc
@@ -245,7 +245,11 @@
  public:
   TestContentAutofillDriver(content::RenderFrameHost* rfh,
                             AutofillClient* client)
-      : ContentAutofillDriver(rfh, client, kAppLocale, kDownloadState) {
+      : ContentAutofillDriver(rfh,
+                              client,
+                              kAppLocale,
+                              kDownloadState,
+                              nullptr) {
     std::unique_ptr<AutofillManager> autofill_manager(
         new MockAutofillManager(this, client));
     SetAutofillManager(std::move(autofill_manager));
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index 945549f..8df5533 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -40,6 +40,10 @@
     "autofill_external_delegate.h",
     "autofill_field.cc",
     "autofill_field.h",
+    "autofill_handler.cc",
+    "autofill_handler.h",
+    "autofill_handler_proxy.cc",
+    "autofill_handler_proxy.h",
     "autofill_ie_toolbar_import_win.cc",
     "autofill_ie_toolbar_import_win.h",
     "autofill_manager.cc",
@@ -52,6 +56,8 @@
     "autofill_profile.h",
     "autofill_profile_comparator.cc",
     "autofill_profile_comparator.h",
+    "autofill_provider.cc",
+    "autofill_provider.h",
     "autofill_scanner.cc",
     "autofill_scanner.h",
     "autofill_type.cc",
diff --git a/components/autofill/core/browser/autofill_handler.cc b/components/autofill/core/browser/autofill_handler.cc
new file mode 100644
index 0000000..f0328d6
--- /dev/null
+++ b/components/autofill/core/browser/autofill_handler.cc
@@ -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.
+
+#include "components/autofill/core/browser/autofill_handler.h"
+
+#include "components/autofill/core/common/autofill_data_validation.h"
+#include "ui/gfx/geometry/rect_f.h"
+
+namespace autofill {
+
+using base::TimeTicks;
+
+AutofillHandler::AutofillHandler(AutofillDriver* driver) : driver_(driver) {}
+
+AutofillHandler::~AutofillHandler() {}
+
+bool AutofillHandler::OnWillSubmitForm(const FormData& form,
+                                       const TimeTicks timestamp) {
+  if (!IsValidFormData(form))
+    return false;
+
+  return OnWillSubmitFormImpl(form, timestamp);
+}
+
+void AutofillHandler::OnTextFieldDidChange(const FormData& form,
+                                           const FormFieldData& field,
+                                           const TimeTicks timestamp) {
+  if (!IsValidFormData(form) || !IsValidFormFieldData(field))
+    return;
+
+  OnTextFieldDidChangeImpl(form, field, timestamp);
+}
+
+void AutofillHandler::OnQueryFormFieldAutofill(int query_id,
+                                               const FormData& form,
+                                               const FormFieldData& field,
+                                               const gfx::RectF& bounding_box) {
+  if (!IsValidFormData(form) || !IsValidFormFieldData(field))
+    return;
+
+  gfx::RectF transformed_box =
+      driver_->TransformBoundingBoxToViewportCoordinates(bounding_box);
+
+  OnQueryFormFieldAutofillImpl(query_id, form, field, transformed_box);
+}
+
+void AutofillHandler::SendFormDataToRenderer(
+    int query_id,
+    AutofillDriver::RendererFormDataAction action,
+    const FormData& data) {
+  driver_->SendFormDataToRenderer(query_id, action, data);
+}
+
+}  // namespace autofill
diff --git a/components/autofill/core/browser/autofill_handler.h b/components/autofill/core/browser/autofill_handler.h
new file mode 100644
index 0000000..e1c9bc19
--- /dev/null
+++ b/components/autofill/core/browser/autofill_handler.h
@@ -0,0 +1,126 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_HANDLER_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_HANDLER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "components/autofill/core/browser/autofill_driver.h"
+#include "components/autofill/core/common/form_data.h"
+
+namespace gfx {
+class RectF;
+}
+
+namespace autofill {
+
+struct FormData;
+struct FormFieldData;
+
+// This class defines the interface should be implemented by autofill
+// implementation in browser side to interact with AutofillDriver.
+class AutofillHandler {
+ public:
+  enum AutofillDownloadManagerState {
+    ENABLE_AUTOFILL_DOWNLOAD_MANAGER,
+    DISABLE_AUTOFILL_DOWNLOAD_MANAGER,
+  };
+
+  virtual ~AutofillHandler();
+
+  // Invoked when the value of textfield is changed.
+  void OnTextFieldDidChange(const FormData& form,
+                            const FormFieldData& field,
+                            const base::TimeTicks timestamp);
+
+  // Invoked when the |form| needs to be autofilled, the |bounding_box| is
+  // a window relative value of |field|.
+  void OnQueryFormFieldAutofill(int query_id,
+                                const FormData& form,
+                                const FormFieldData& field,
+                                const gfx::RectF& bounding_box);
+
+  // Invoked when the specified form will be submitted, returns false if this
+  // form is not relevant for Autofill.
+  //
+  // IMPORTANT: On iOS, this method is called when the form is submitted,
+  // immediately before OnFormSubmitted() is called. Do not assume that
+  // OnWillSubmitForm() will run before the form submits.
+  // TODO(mathp): Revisit this and use a single method to track form submission.
+  //
+  // Processes the about-to-be-submitted |form|, uploading the possible field
+  // types for the submitted fields to the crowdsourcing server.
+  bool OnWillSubmitForm(const FormData& form, const base::TimeTicks timestamp);
+
+  // Invoked when focus is no longer on form.
+  virtual void OnFocusNoLongerOnForm() = 0;
+
+  // Invoked when |form| has been filled with the value given by
+  // SendFormDataToRenderer.
+  virtual void OnDidFillAutofillFormData(const FormData& form,
+                                         const base::TimeTicks timestamp) = 0;
+
+  // Invoked when preview autofill value has been shown.
+  virtual void OnDidPreviewAutofillFormData() = 0;
+
+  // Invoked when |forms| has been detected.
+  virtual void OnFormsSeen(const std::vector<FormData>& forms,
+                           const base::TimeTicks timestamp) = 0;
+
+  // Invoked when |form| has been submitted.
+  // Processes the submitted |form|, saving any new Autofill data to the user's
+  // personal profile. Returns false if this form is not relevant for Autofill.
+  virtual bool OnFormSubmitted(const FormData& form) = 0;
+
+  // Invoked when textfeild editing ended
+  virtual void OnDidEndTextFieldEditing() = 0;
+
+  // Invoked when popup window should be hidden.
+  virtual void OnHidePopup() = 0;
+
+  // Invoked when data list need to be set.
+  virtual void OnSetDataList(const std::vector<base::string16>& values,
+                             const std::vector<base::string16>& labels) = 0;
+
+  // Resets cache.
+  virtual void Reset() = 0;
+
+  // Send the form |data| to renderer for the specified |action|.
+  void SendFormDataToRenderer(int query_id,
+                              AutofillDriver::RendererFormDataAction action,
+                              const FormData& data);
+
+ protected:
+  AutofillHandler(AutofillDriver* driver);
+
+  virtual bool OnWillSubmitFormImpl(const FormData& form,
+                                    const base::TimeTicks timestamp) = 0;
+
+  virtual void OnTextFieldDidChangeImpl(const FormData& form,
+                                        const FormFieldData& field,
+                                        const base::TimeTicks timestamp) = 0;
+
+  virtual void OnQueryFormFieldAutofillImpl(int query_id,
+                                            const FormData& form,
+                                            const FormFieldData& field,
+                                            const gfx::RectF& bounding_box) = 0;
+
+  AutofillDriver* driver() { return driver_; }
+
+ private:
+  // Provides driver-level context to the shared code of the component. Must
+  // outlive this object.
+  AutofillDriver* driver_;
+
+  DISALLOW_COPY_AND_ASSIGN(AutofillHandler);
+};
+
+}  // namespace autofill
+
+#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_HANDLER_H_
diff --git a/components/autofill/core/browser/autofill_handler_proxy.cc b/components/autofill/core/browser/autofill_handler_proxy.cc
new file mode 100644
index 0000000..842d0b7
--- /dev/null
+++ b/components/autofill/core/browser/autofill_handler_proxy.cc
@@ -0,0 +1,70 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/core/browser/autofill_handler_proxy.h"
+
+#include "components/autofill/core/browser/autofill_provider.h"
+
+namespace autofill {
+
+using base::TimeTicks;
+
+AutofillHandlerProxy::AutofillHandlerProxy(AutofillDriver* driver,
+                                           AutofillProvider* provider)
+    : AutofillHandler(driver), provider_(provider), weak_ptr_factory_(this) {}
+
+AutofillHandlerProxy::~AutofillHandlerProxy() {}
+
+bool AutofillHandlerProxy::OnWillSubmitFormImpl(const FormData& form,
+                                                const TimeTicks timestamp) {
+  return provider_->OnWillSubmitForm(this, form, timestamp);
+}
+
+void AutofillHandlerProxy::OnTextFieldDidChangeImpl(const FormData& form,
+                                                    const FormFieldData& field,
+                                                    const TimeTicks timestamp) {
+  provider_->OnTextFieldDidChange(this, form, field, timestamp);
+}
+
+void AutofillHandlerProxy::OnQueryFormFieldAutofillImpl(
+    int query_id,
+    const FormData& form,
+    const FormFieldData& field,
+    const gfx::RectF& bounding_box) {
+  provider_->OnQueryFormFieldAutofill(this, query_id, form, field,
+                                      bounding_box);
+}
+
+void AutofillHandlerProxy::OnFocusNoLongerOnForm() {
+  provider_->OnFocusNoLongerOnForm(this);
+}
+
+void AutofillHandlerProxy::OnDidFillAutofillFormData(
+    const FormData& form,
+    const base::TimeTicks timestamp) {
+  provider_->OnDidFillAutofillFormData(this, form, timestamp);
+}
+
+void AutofillHandlerProxy::OnDidPreviewAutofillFormData() {}
+
+void AutofillHandlerProxy::OnFormsSeen(const std::vector<FormData>& forms,
+                                       const base::TimeTicks timestamp) {}
+
+bool AutofillHandlerProxy::OnFormSubmitted(const FormData& form) {
+  return false;
+}
+
+void AutofillHandlerProxy::OnDidEndTextFieldEditing() {}
+
+void AutofillHandlerProxy::OnHidePopup() {}
+
+void AutofillHandlerProxy::OnSetDataList(
+    const std::vector<base::string16>& values,
+    const std::vector<base::string16>& labels) {}
+
+void AutofillHandlerProxy::Reset() {
+  provider_->Reset(this);
+}
+
+}  // namespace autofill
diff --git a/components/autofill/core/browser/autofill_handler_proxy.h b/components/autofill/core/browser/autofill_handler_proxy.h
new file mode 100644
index 0000000..3616ab9
--- /dev/null
+++ b/components/autofill/core/browser/autofill_handler_proxy.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 COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_HANDLER_PROXY_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_HANDLER_PROXY_H_
+
+#include "base/memory/weak_ptr.h"
+#include "components/autofill/core/browser/autofill_handler.h"
+
+namespace autofill {
+
+class AutofillProvider;
+
+// This class forwards AutofillHandler calls to AutofillProvider.
+class AutofillHandlerProxy : public AutofillHandler {
+ public:
+  AutofillHandlerProxy(AutofillDriver* driver, AutofillProvider* provider);
+  ~AutofillHandlerProxy() override;
+
+  void OnFocusNoLongerOnForm() override;
+
+  void OnDidFillAutofillFormData(const FormData& form,
+                                 const base::TimeTicks timestamp) override;
+
+  void OnDidPreviewAutofillFormData() override;
+
+  void OnFormsSeen(const std::vector<FormData>& forms,
+                   const base::TimeTicks timestamp) override;
+
+  bool OnFormSubmitted(const FormData& form) override;
+
+  void OnDidEndTextFieldEditing() override;
+  void OnHidePopup() override;
+  void OnSetDataList(const std::vector<base::string16>& values,
+                     const std::vector<base::string16>& labels) override;
+
+  void Reset() override;
+
+  base::WeakPtr<AutofillHandlerProxy> GetWeakPtr() {
+    return weak_ptr_factory_.GetWeakPtr();
+  }
+
+ protected:
+  bool OnWillSubmitFormImpl(const FormData& form,
+                            const base::TimeTicks timestamp) override;
+
+  void OnTextFieldDidChangeImpl(const FormData& form,
+                                const FormFieldData& field,
+                                const base::TimeTicks timestamp) override;
+
+  void OnQueryFormFieldAutofillImpl(int query_id,
+                                    const FormData& form,
+                                    const FormFieldData& field,
+                                    const gfx::RectF& bounding_box) override;
+
+ private:
+  AutofillProvider* provider_;
+  base::WeakPtrFactory<AutofillHandlerProxy> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(AutofillHandlerProxy);
+};
+
+}  // namespace autofill
+
+#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_HANDLER_PROXY_H_
diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc
index c3b4d6b..ed9915a 100644
--- a/components/autofill/core/browser/autofill_manager.cc
+++ b/components/autofill/core/browser/autofill_manager.cc
@@ -219,7 +219,7 @@
     AutofillClient* client,
     const std::string& app_locale,
     AutofillDownloadManagerState enable_download_manager)
-    : driver_(driver),
+    : AutofillHandler(driver),
       client_(client),
       payments_client_(base::MakeUnique<payments::PaymentsClient>(
           driver->GetURLRequestContext(),
@@ -263,8 +263,8 @@
   if (personal_data_ && client_)
     personal_data_->OnSyncServiceInitialized(client_->GetSyncService());
 
-  if (personal_data_ && driver_)
-    personal_data_->SetURLRequestContextGetter(driver_->GetURLRequestContext());
+  if (personal_data_ && driver)
+    personal_data_->SetURLRequestContextGetter(driver->GetURLRequestContext());
 }
 
 AutofillManager::~AutofillManager() {}
@@ -369,11 +369,11 @@
 }
 
 void AutofillManager::OnFormsSeen(const std::vector<FormData>& forms,
-                                  const TimeTicks& timestamp) {
+                                  const TimeTicks timestamp) {
   if (!IsValidFormDataVector(forms))
     return;
 
-  if (!driver_->RendererIsAvailable())
+  if (!driver()->RendererIsAvailable())
     return;
 
   bool enabled = IsAutofillEnabled();
@@ -392,11 +392,8 @@
   ParseForms(forms);
 }
 
-bool AutofillManager::OnWillSubmitForm(const FormData& form,
-                                       const TimeTicks& timestamp) {
-  if (!IsValidFormData(form))
-    return false;
-
+bool AutofillManager::OnWillSubmitFormImpl(const FormData& form,
+                                           const TimeTicks timestamp) {
   // We will always give Autocomplete a chance to save the data.
   std::unique_ptr<FormStructure> submitted_form = ValidateSubmittedForm(form);
   if (!submitted_form) {
@@ -516,12 +513,9 @@
   StartUploadProcess(std::move(upload_form), TimeTicks::Now(), false);
 }
 
-void AutofillManager::OnTextFieldDidChange(const FormData& form,
-                                           const FormFieldData& field,
-                                           const TimeTicks& timestamp) {
-  if (!IsValidFormData(form) || !IsValidFormFieldData(field))
-    return;
-
+void AutofillManager::OnTextFieldDidChangeImpl(const FormData& form,
+                                               const FormFieldData& field,
+                                               const TimeTicks timestamp) {
   if (test_delegate_)
     test_delegate_->OnTextFieldChanged();
 
@@ -561,16 +555,11 @@
          (form.action.is_valid() && form.action.SchemeIs("http"));
 }
 
-void AutofillManager::OnQueryFormFieldAutofill(int query_id,
-                                               const FormData& form,
-                                               const FormFieldData& field,
-                                               const gfx::RectF& bounding_box) {
-  if (!IsValidFormData(form) || !IsValidFormFieldData(field))
-    return;
-
-  gfx::RectF transformed_box =
-      driver_->TransformBoundingBoxToViewportCoordinates(bounding_box);
-
+void AutofillManager::OnQueryFormFieldAutofillImpl(
+    int query_id,
+    const FormData& form,
+    const FormFieldData& field,
+    const gfx::RectF& transformed_box) {
   external_delegate_->OnQuery(query_id, form, field, transformed_box);
 
   // Need to refresh models before using the form_event_loggers.
@@ -589,7 +578,7 @@
   if (got_autofillable_form) {
     if (autofill_field->Type().group() == CREDIT_CARD) {
       is_filling_credit_card = true;
-      driver_->DidInteractWithCreditCardForm();
+      driver()->DidInteractWithCreditCardForm();
       credit_card_form_event_logger_->OnDidInteractWithAutofillableForm();
     } else {
       address_form_event_logger_->OnDidInteractWithAutofillableForm();
@@ -601,12 +590,11 @@
   const bool is_http_warning_enabled =
       security_state::IsHttpWarningInFormEnabled();
 
-  // TODO(rogerm): Early exit here on !driver_->RendererIsAvailable()?
+  // TODO(rogerm): Early exit here on !driver()->RendererIsAvailable()?
   // We skip populating autofill data, but might generate warnings and or
   // signin promo to show over the unavailable renderer. That seems a mistake.
 
-  if (is_autofill_possible &&
-      driver_->RendererIsAvailable() &&
+  if (is_autofill_possible && driver()->RendererIsAvailable() &&
       got_autofillable_form) {
     // On desktop, don't return non credit card related suggestions for forms or
     // fields that have the "autocomplete" attribute set to off.
@@ -794,7 +782,7 @@
   // NOTE: RefreshDataModels may invalidate |data_model| because it causes the
   // PersonalDataManager to reload Mac address book entries. Thus it must come
   // before GetProfile or GetCreditCard.
-  if (!RefreshDataModels() || !driver_->RendererIsAvailable())
+  if (!RefreshDataModels() || !driver()->RendererIsAvailable())
     return;
 
   const CreditCard* credit_card = nullptr;
@@ -811,7 +799,7 @@
                                          const CreditCard& credit_card,
                                          const base::string16& cvc) {
   if (!IsValidFormData(form) || !IsValidFormFieldData(field) ||
-      !driver_->RendererIsAvailable()) {
+      !driver()->RendererIsAvailable()) {
     return;
   }
 
@@ -829,7 +817,7 @@
 }
 
 void AutofillManager::OnDidFillAutofillFormData(const FormData& form,
-                                                const TimeTicks& timestamp) {
+                                                const TimeTicks timestamp) {
   if (test_delegate_)
     test_delegate_->DidFillFormData();
 
@@ -1028,10 +1016,10 @@
 
   // Forward form structures to the password generation manager to detect
   // account creation forms.
-  driver_->PropagateAutofillPredictions(queried_forms);
+  driver()->PropagateAutofillPredictions(queried_forms);
 
   // If the corresponding flag is set, annotate forms with the predicted types.
-  driver_->SendAutofillTypePredictionsToRenderer(queried_forms);
+  driver()->SendAutofillTypePredictionsToRenderer(queried_forms);
 }
 
 IdentityProvider* AutofillManager::GetIdentityProvider() {
@@ -1120,7 +1108,7 @@
 }
 
 void AutofillManager::OnFullCardRequestFailed() {
-  driver_->RendererShouldClearPreviewedForm();
+  driver()->RendererShouldClearPreviewedForm();
 }
 
 void AutofillManager::ShowUnmaskPrompt(
@@ -1180,7 +1168,7 @@
 }
 
 bool AutofillManager::ShouldUploadForm(const FormStructure& form) {
-  return IsAutofillEnabled() && !driver_->IsIncognito() &&
+  return IsAutofillEnabled() && !driver()->IsIncognito() &&
          form.ShouldBeParsed() &&
          (form.active_field_count() >= kRequiredFieldsForUpload ||
           (form.all_fields_are_passwords() &&
@@ -1596,7 +1584,7 @@
 AutofillManager::AutofillManager(AutofillDriver* driver,
                                  AutofillClient* client,
                                  PersonalDataManager* personal_data)
-    : driver_(driver),
+    : AutofillHandler(driver),
       client_(client),
       payments_client_(base::MakeUnique<payments::PaymentsClient>(
           driver->GetURLRequestContext(),
@@ -1629,7 +1617,7 @@
       autofill_assistant_(this),
 #endif
       weak_ptr_factory_(this) {
-  DCHECK(driver_);
+  DCHECK(driver);
   DCHECK(client_);
   CountryNames::SetLocaleString(app_locale_);
 }
@@ -1766,7 +1754,7 @@
     if (action == AutofillDriver::FORM_DATA_ACTION_FILL)
       personal_data_->RecordUseOf(data_model);
 
-    driver_->SendFormDataToRenderer(query_id, action, result);
+    driver()->SendFormDataToRenderer(query_id, action, result);
     return;
   }
 
@@ -1837,7 +1825,7 @@
   if (action == AutofillDriver::FORM_DATA_ACTION_FILL)
     personal_data_->RecordUseOf(data_model);
 
-  driver_->SendFormDataToRenderer(query_id, action, result);
+  driver()->SendFormDataToRenderer(query_id, action, result);
 }
 
 std::unique_ptr<FormStructure> AutofillManager::ValidateSubmittedForm(
@@ -1960,7 +1948,7 @@
     (*updated_form)->UpdateFromCache(*cached_form, true);
 
   // Annotate the updated form with its predicted types.
-  driver_->SendAutofillTypePredictionsToRenderer({*updated_form});
+  driver()->SendAutofillTypePredictionsToRenderer({*updated_form});
 
   return true;
 }
@@ -2074,7 +2062,7 @@
   // For the |non_queryable_forms|, we have all the field type info we're ever
   // going to get about them.  For the other forms, we'll wait until we get a
   // response from the server.
-  driver_->SendAutofillTypePredictionsToRenderer(non_queryable_forms);
+  driver()->SendAutofillTypePredictionsToRenderer(non_queryable_forms);
 }
 
 bool AutofillManager::ParseForm(const FormData& form,
diff --git a/components/autofill/core/browser/autofill_manager.h b/components/autofill/core/browser/autofill_manager.h
index a0d75140..1fc3e6df 100644
--- a/components/autofill/core/browser/autofill_manager.h
+++ b/components/autofill/core/browser/autofill_manager.h
@@ -23,6 +23,7 @@
 #include "components/autofill/core/browser/autofill_client.h"
 #include "components/autofill/core/browser/autofill_download_manager.h"
 #include "components/autofill/core/browser/autofill_driver.h"
+#include "components/autofill/core/browser/autofill_handler.h"
 #include "components/autofill/core/browser/autofill_metrics.h"
 #include "components/autofill/core/browser/card_unmask_delegate.h"
 #include "components/autofill/core/browser/form_structure.h"
@@ -72,16 +73,12 @@
 
 // Manages saving and restoring the user's personal information entered into web
 // forms. One per frame; owned by the AutofillDriver.
-class AutofillManager : public AutofillDownloadManager::Observer,
+class AutofillManager : public AutofillHandler,
+                        public AutofillDownloadManager::Observer,
                         public payments::PaymentsClientDelegate,
                         public payments::FullCardRequest::ResultDelegate,
                         public payments::FullCardRequest::UIDelegate {
  public:
-  enum AutofillDownloadManagerState {
-    ENABLE_AUTOFILL_DOWNLOAD_MANAGER,
-    DISABLE_AUTOFILL_DOWNLOAD_MANAGER,
-  };
-
   // Registers our Enable/Disable Autofill pref.
   static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
 
@@ -123,10 +120,6 @@
   void DidShowSuggestions(bool is_new_popup,
                           const FormData& form,
                           const FormFieldData& field);
-  void OnFocusNoLongerOnForm();
-  void OnDidFillAutofillFormData(const FormData& form,
-                                 const base::TimeTicks& timestamp);
-  void OnDidPreviewAutofillFormData();
 
   // Returns true if the value/identifier is deletable. Fills out
   // |title| and |body| with relevant user-facing text.
@@ -167,25 +160,8 @@
   // Only for testing.
   void SetTestDelegate(AutofillManagerTestDelegate* delegate);
 
-  void OnFormsSeen(const std::vector<FormData>& forms,
-                   const base::TimeTicks& timestamp);
-
   void set_app_locale(std::string app_locale) { app_locale_ = app_locale; }
 
-  // IMPORTANT: On iOS, this method is called when the form is submitted,
-  // immediately before OnFormSubmitted() is called. Do not assume that
-  // OnWillSubmitForm() will run before the form submits.
-  // TODO(mathp): Revisit this and use a single method to track form submission.
-  //
-  // Processes the about-to-be-submitted |form|, uploading the possible field
-  // types for the submitted fields to the crowdsourcing server. Returns false
-  // if this form is not relevant for Autofill.
-  bool OnWillSubmitForm(const FormData& form, const base::TimeTicks& timestamp);
-
-  // Processes the submitted |form|, saving any new Autofill data to the user's
-  // personal profile. Returns false if this form is not relevant for Autofill.
-  bool OnFormSubmitted(const FormData& form);
-
   // Will send an upload based on the |form_structure| data and the local
   // Autofill profile data. |observed_submission| is specified if the upload
   // follows an observed submission event.
@@ -200,22 +176,19 @@
   // Upload the current pending form.
   void ProcessPendingFormForUpload();
 
-  void OnTextFieldDidChange(const FormData& form,
-                            const FormFieldData& field,
-                            const base::TimeTicks& timestamp);
-
-  // The |bounding_box| is a window relative value.
-  void OnQueryFormFieldAutofill(int query_id,
-                                const FormData& form,
-                                const FormFieldData& field,
-                                const gfx::RectF& bounding_box);
-  void OnDidEndTextFieldEditing();
-  void OnHidePopup();
+  // AutofillHandler:
+  void OnFocusNoLongerOnForm() override;
+  void OnDidFillAutofillFormData(const FormData& form,
+                                 const base::TimeTicks timestamp) override;
+  void OnDidPreviewAutofillFormData() override;
+  void OnFormsSeen(const std::vector<FormData>& forms,
+                   const base::TimeTicks timestamp) override;
+  bool OnFormSubmitted(const FormData& form) override;
+  void OnDidEndTextFieldEditing() override;
+  void OnHidePopup() override;
   void OnSetDataList(const std::vector<base::string16>& values,
-                     const std::vector<base::string16>& labels);
-
-  // Resets cache.
-  virtual void Reset();
+                     const std::vector<base::string16>& labels) override;
+  void Reset() override;
 
   // Returns the value of the AutofillEnabled pref.
   virtual bool IsAutofillEnabled() const;
@@ -264,6 +237,17 @@
                        std::string* cc_backend_id,
                        std::string* profile_backend_id) const;
 
+  // AutofillHandler:
+  bool OnWillSubmitFormImpl(const FormData& form,
+                            const base::TimeTicks timestamp) override;
+  void OnTextFieldDidChangeImpl(const FormData& form,
+                                const FormFieldData& field,
+                                const base::TimeTicks timestamp) override;
+  void OnQueryFormFieldAutofillImpl(int query_id,
+                                    const FormData& form,
+                                    const FormFieldData& field,
+                                    const gfx::RectF& transformed_box) override;
+
   std::vector<std::unique_ptr<FormStructure>>* form_structures() {
     return &form_structures_;
   }
@@ -497,10 +481,6 @@
   // |AutofillMetrics::CardUploadDecisionMetric|.
   void LogCardUploadDecisions(int upload_decision_metrics);
 
-  // Provides driver-level context to the shared code of the component. Must
-  // outlive this object.
-  AutofillDriver* driver_;
-
   AutofillClient* const client_;
 
   // Handles Payments service requests.
diff --git a/components/autofill/core/browser/autofill_provider.cc b/components/autofill/core/browser/autofill_provider.cc
new file mode 100644
index 0000000..9fc3b8c0
--- /dev/null
+++ b/components/autofill/core/browser/autofill_provider.cc
@@ -0,0 +1,22 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/core/browser/autofill_provider.h"
+
+#include "components/autofill/core/browser/autofill_handler_proxy.h"
+
+namespace autofill {
+
+AutofillProvider::AutofillProvider() {}
+
+AutofillProvider::~AutofillProvider() {}
+
+void AutofillProvider::SendFormDataToRenderer(AutofillHandlerProxy* handler,
+                                              int requestId,
+                                              const FormData& formData) {
+  handler->SendFormDataToRenderer(
+      requestId, AutofillDriver::FORM_DATA_ACTION_FILL, formData);
+}
+
+}  // namespace autofil
diff --git a/components/autofill/core/browser/autofill_provider.h b/components/autofill/core/browser/autofill_provider.h
new file mode 100644
index 0000000..5c6e9cc
--- /dev/null
+++ b/components/autofill/core/browser/autofill_provider.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_AUTOFILL_CORE_BROWSER_AUTOFILL_PROVIDER_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_PROVIDER_H_
+
+#include "base/time/time.h"
+#include "components/autofill/core/common/form_data.h"
+
+namespace gfx {
+class RectF;
+}
+
+namespace autofill {
+
+class AutofillHandlerProxy;
+
+// This class defines the interface for the autofill implementation other than
+// default AutofillManager.
+class AutofillProvider {
+ public:
+  AutofillProvider();
+  virtual ~AutofillProvider();
+
+  virtual void OnQueryFormFieldAutofill(AutofillHandlerProxy* handler,
+                                        int32_t id,
+                                        const FormData& form,
+                                        const FormFieldData& field,
+                                        const gfx::RectF& bounding_box) = 0;
+
+  virtual void OnTextFieldDidChange(AutofillHandlerProxy* handler,
+                                    const FormData& form,
+                                    const FormFieldData& field,
+                                    const base::TimeTicks timestamp) = 0;
+
+  virtual bool OnWillSubmitForm(AutofillHandlerProxy* handler,
+                                const FormData& form,
+                                const base::TimeTicks timestamp) = 0;
+
+  virtual void OnFocusNoLongerOnForm(AutofillHandlerProxy* handler) = 0;
+
+  virtual void OnDidFillAutofillFormData(AutofillHandlerProxy* handler,
+                                         const FormData& form,
+                                         base::TimeTicks timestamp) = 0;
+
+  virtual void Reset(AutofillHandlerProxy* handler) = 0;
+
+  void SendFormDataToRenderer(AutofillHandlerProxy* handler,
+                              int requestId,
+                              const FormData& formData);
+};
+}
+
+#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_PROVIDER_H_
diff --git a/components/autofill/core/common/form_data.cc b/components/autofill/core/common/form_data.cc
index 47137bb7..81de550a 100644
--- a/components/autofill/core/common/form_data.cc
+++ b/components/autofill/core/common/form_data.cc
@@ -86,6 +86,19 @@
   return true;
 }
 
+bool FormData::SimilarFormAs(const FormData& form) const {
+  if (name != form.name || origin != form.origin || action != form.action ||
+      is_form_tag != form.is_form_tag ||
+      is_formless_checkout != form.is_formless_checkout ||
+      fields.size() != form.fields.size())
+    return false;
+  for (size_t i = 0; i < fields.size(); ++i) {
+    if (!fields[i].SimilarFieldAs(form.fields[i]))
+      return false;
+  }
+  return true;
+}
+
 bool FormData::operator==(const FormData& form) const {
   return name == form.name && origin == form.origin && action == form.action &&
          is_form_tag == form.is_form_tag &&
diff --git a/components/autofill/core/common/form_data.h b/components/autofill/core/common/form_data.h
index a4397fc..5e5a429 100644
--- a/components/autofill/core/common/form_data.h
+++ b/components/autofill/core/common/form_data.h
@@ -23,6 +23,10 @@
   // form elements.
   bool SameFormAs(const FormData& other) const;
 
+  // Same as SameFormAs() except calling FormFieldData.SimilarFieldAs() to
+  // compare fields.
+  bool SimilarFormAs(const FormData& other) const;
+
   // Note: operator==() performs a full-field-comparison(byte by byte), this is
   // different from SameFormAs(), which ignores comparison for those "values" of
   // all form fields, just like what FormFieldData::SameFieldAs() ignores.
diff --git a/components/autofill/core/common/form_field_data.cc b/components/autofill/core/common/form_field_data.cc
index 48796627..89c35362 100644
--- a/components/autofill/core/common/form_field_data.cc
+++ b/components/autofill/core/common/form_field_data.cc
@@ -159,6 +159,12 @@
   // should not be considered changes in the structure of the form.
 }
 
+bool FormFieldData::SimilarFieldAs(const FormFieldData& field) const {
+  return label == field.label && name == field.name && id == field.id &&
+         form_control_type == field.form_control_type &&
+         IsCheckable(check_status) == IsCheckable(field.check_status);
+}
+
 bool FormFieldData::operator==(const FormFieldData& field) const {
   return SameFieldAs(field) && is_autofilled == field.is_autofilled &&
          check_status == field.check_status &&
diff --git a/components/autofill/core/common/form_field_data.h b/components/autofill/core/common/form_field_data.h
index a4de0a2..1466bed 100644
--- a/components/autofill/core/common/form_field_data.h
+++ b/components/autofill/core/common/form_field_data.h
@@ -56,6 +56,13 @@
   // Returns true if two form fields are the same, not counting the value.
   bool SameFieldAs(const FormFieldData& field) const;
 
+  // SameFieldAs() is a little restricted when field's style changed
+  // dynamically, like css.
+  // This method only compares critical attributes of field to check whether
+  // they are similar enough to be considered as same field if form's
+  // other information isn't changed.
+  bool SimilarFieldAs(const FormFieldData& field) const;
+
   // Note: operator==() performs a full-field-comparison(byte by byte), this is
   // different from SameFieldAs(), which ignores comparison for those "values"
   // not regarded as part of identity of the field, such as is_autofilled and
diff --git a/components/cronet/android/java/src/org/chromium/net/impl/CronetLibraryLoader.java b/components/cronet/android/java/src/org/chromium/net/impl/CronetLibraryLoader.java
index 42066ef..c956ac0 100644
--- a/components/cronet/android/java/src/org/chromium/net/impl/CronetLibraryLoader.java
+++ b/components/cronet/android/java/src/org/chromium/net/impl/CronetLibraryLoader.java
@@ -43,7 +43,7 @@
      * any thread, the load and initialization is performed on init thread.
      */
     public static void ensureInitialized(
-            final Context applicationContext, final CronetEngineBuilderImpl builder) {
+            Context applicationContext, final CronetEngineBuilderImpl builder) {
         synchronized (sLoadLock) {
             if (!sInitThreadInitDone) {
                 ContextUtils.initApplicationContext(applicationContext);
@@ -53,7 +53,7 @@
                 postToInitThread(new Runnable() {
                     @Override
                     public void run() {
-                        ensureInitializedOnInitThread(applicationContext);
+                        ensureInitializedOnInitThread();
                     }
                 });
             }
@@ -89,12 +89,12 @@
      * the init thread. Ensures that the NetworkChangeNotifier is initialzied and the
      * init thread native MessageLoop is initialized.
      */
-    static void ensureInitializedOnInitThread(Context context) {
+    static void ensureInitializedOnInitThread() {
         assert onInitThread();
         if (sInitThreadInitDone) {
             return;
         }
-        NetworkChangeNotifier.init(context);
+        NetworkChangeNotifier.init();
         // Registers to always receive network notifications. Note
         // that this call is fine for Cronet because Cronet
         // embedders do not have API access to create network change
diff --git a/components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequestContext.java b/components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequestContext.java
index f4747a4..837d3a4 100644
--- a/components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequestContext.java
+++ b/components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequestContext.java
@@ -165,7 +165,7 @@
         CronetLibraryLoader.postToInitThread(new Runnable() {
             @Override
             public void run() {
-                CronetLibraryLoader.ensureInitializedOnInitThread(builder.getContext());
+                CronetLibraryLoader.ensureInitializedOnInitThread();
                 synchronized (mLock) {
                     // mUrlRequestContextAdapter is guaranteed to exist until
                     // initialization on init and network threads completes and
diff --git a/components/cryptauth/remote_device.cc b/components/cryptauth/remote_device.cc
index e3d26d0..b9556956e 100644
--- a/components/cryptauth/remote_device.cc
+++ b/components/cryptauth/remote_device.cc
@@ -45,8 +45,7 @@
       public_key(public_key),
       bluetooth_address(bluetooth_address),
       persistent_symmetric_key(persistent_symmetric_key),
-      sign_in_challenge(sign_in_challenge),
-      are_beacon_seeds_loaded(false) {}
+      sign_in_challenge(sign_in_challenge) {}
 
 RemoteDevice::RemoteDevice(const RemoteDevice& other) = default;
 
diff --git a/components/cryptauth/remote_device.h b/components/cryptauth/remote_device.h
index cd4085f8..7662b1a 100644
--- a/components/cryptauth/remote_device.h
+++ b/components/cryptauth/remote_device.h
@@ -23,7 +23,7 @@
 
   // Note: To save space, the BeaconSeeds may not necessarily be included in
   // this object.
-  bool are_beacon_seeds_loaded;
+  bool are_beacon_seeds_loaded = false;
   std::vector<BeaconSeed> beacon_seeds;
 
   RemoteDevice();
diff --git a/components/data_use_measurement/core/data_use_recorder.cc b/components/data_use_measurement/core/data_use_recorder.cc
index f9a38704..732796e1 100644
--- a/components/data_use_measurement/core/data_use_recorder.cc
+++ b/components/data_use_measurement/core/data_use_recorder.cc
@@ -53,10 +53,6 @@
   pending_data_sources_.erase(source);
 }
 
-bool DataUseRecorder::HasPendingURLRequest(net::URLRequest* request) {
-  return pending_url_requests_.find(request) != pending_url_requests_.end();
-}
-
 void DataUseRecorder::MergeFrom(DataUseRecorder* other) {
   data_use_.MergeFrom(other->data_use());
 }
diff --git a/components/data_use_measurement/core/data_use_recorder.h b/components/data_use_measurement/core/data_use_recorder.h
index 2fee7bf04..9cebd99 100644
--- a/components/data_use_measurement/core/data_use_recorder.h
+++ b/components/data_use_measurement/core/data_use_recorder.h
@@ -61,10 +61,6 @@
   // recorder.
   void RemoveAllPendingURLRequests();
 
-  // Returns whether there are any pending URLRequests whose data use is tracked
-  // by this DataUseRecorder.
-  bool HasPendingURLRequest(net::URLRequest* request);
-
   // Merge another DataUseRecorder to this instance.
   void MergeFrom(DataUseRecorder* other);
 
diff --git a/components/exo/shell_surface.cc b/components/exo/shell_surface.cc
index 240197fe..a87a22a 100644
--- a/components/exo/shell_surface.cc
+++ b/components/exo/shell_surface.cc
@@ -11,7 +11,6 @@
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/public/cpp/window_properties.h"
 #include "ash/public/interfaces/window_pin_type.mojom.h"
-#include "ash/shell_port.h"
 #include "ash/wm/drag_window_resizer.h"
 #include "ash/wm/window_resizer.h"
 #include "ash/wm/window_state.h"
@@ -167,10 +166,7 @@
 class CustomWindowResizer : public ash::WindowResizer {
  public:
   explicit CustomWindowResizer(ash::wm::WindowState* window_state)
-      : WindowResizer(window_state) {
-    ash::ShellPort::Get()->LockCursor();
-  }
-  ~CustomWindowResizer() override { ash::ShellPort::Get()->UnlockCursor(); }
+      : WindowResizer(window_state) {}
 
   // Overridden from ash::WindowResizer:
   void Drag(const gfx::Point& location, int event_flags) override {}
@@ -1499,9 +1495,7 @@
   const gfx::Rect widget_bounds = widget_->GetWindowBoundsInScreen();
   if (widget_bounds != new_widget_bounds) {
     if (bounds_mode_ != BoundsMode::CLIENT || !resizer_) {
-      // TODO(domlaskowski): Use screen coordinates once multi-display support
-      // lands in ARC. See crbug.com/718627.
-      widget_->GetNativeWindow()->SetBounds(new_widget_bounds);
+      widget_->SetBounds(new_widget_bounds);
       UpdateSurfaceBounds();
     } else {
       // TODO(domlaskowski): Synchronize window state transitions with the
diff --git a/components/exo/wayland/server.cc b/components/exo/wayland/server.cc
index e541591d..36441f2 100644
--- a/components/exo/wayland/server.cc
+++ b/components/exo/wayland/server.cc
@@ -2185,6 +2185,10 @@
         const gfx::Rect& bounds = display.bounds();
         const gfx::Insets& insets = display.GetWorkAreaInsets();
 
+        double device_scale_factor =
+            WMHelper::GetInstance()->GetDisplayInfo(display.id())
+                .device_scale_factor();
+
         zcr_remote_shell_v1_send_workspace(
             remote_shell_resource_,
             static_cast<uint32_t>(display.id() >> 32),
@@ -2192,7 +2196,8 @@
             bounds.x(), bounds.y(), bounds.width(), bounds.height(),
             insets.left(), insets.top(), insets.right(), insets.bottom(),
             OutputTransform(display.rotation()),
-            wl_fixed_from_double(display.device_scale_factor()));
+            wl_fixed_from_double(device_scale_factor),
+            display.IsInternal());
       }
 
       zcr_remote_shell_v1_send_configure(remote_shell_resource_, layout_mode_);
diff --git a/components/metrics/metrics_service_client.cc b/components/metrics/metrics_service_client.cc
index 8a204b3..4339ad0 100644
--- a/components/metrics/metrics_service_client.cc
+++ b/components/metrics/metrics_service_client.cc
@@ -4,23 +4,10 @@
 
 #include "components/metrics/metrics_service_client.h"
 
-#include "base/feature_list.h"
 #include "components/metrics/url_constants.h"
 
 namespace metrics {
 
-namespace {
-
-#if defined(OS_ANDROID) || defined(OS_IOS)
-const base::Feature kNewMetricsUrlFeature{"NewMetricsUrl",
-                                          base::FEATURE_ENABLED_BY_DEFAULT};
-#else
-const base::Feature kNewMetricsUrlFeature{"NewMetricsUrl",
-                                          base::FEATURE_DISABLED_BY_DEFAULT};
-#endif
-
-}  // namespace
-
 MetricsServiceClient::MetricsServiceClient() : update_running_services_() {}
 
 MetricsServiceClient::~MetricsServiceClient() {}
@@ -46,9 +33,7 @@
 }
 
 std::string MetricsServiceClient::GetMetricsServerUrl() {
-  return base::FeatureList::IsEnabled(kNewMetricsUrlFeature)
-             ? kNewMetricsServerUrl
-             : kOldMetricsServerUrl;
+  return kNewMetricsServerUrl;
 }
 
 bool MetricsServiceClient::IsHistorySyncEnabledOnAllProfiles() {
diff --git a/components/omnibox/browser/omnibox_field_trial.cc b/components/omnibox/browser/omnibox_field_trial.cc
index 1e40681..32433ba 100644
--- a/components/omnibox/browser/omnibox_field_trial.cc
+++ b/components/omnibox/browser/omnibox_field_trial.cc
@@ -42,6 +42,11 @@
 const base::Feature kOmniboxEntitySuggestions{
     "OmniboxEntitySuggestions", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Feature used to force on the experiment of transmission of tail suggestions
+// from GWS to this client, currently testing for desktop.
+const base::Feature kOmniboxTailSuggestions{
+    "OmniboxTailSuggestions", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Feature used to enable clipboard provider, which provides the user with
 // suggestions of the URL in the user's clipboard (if any) upon omnibox focus.
 const base::Feature kEnableClipboardProvider {
diff --git a/components/omnibox/browser/omnibox_field_trial.h b/components/omnibox/browser/omnibox_field_trial.h
index 2033183..42b9758 100644
--- a/components/omnibox/browser/omnibox_field_trial.h
+++ b/components/omnibox/browser/omnibox_field_trial.h
@@ -26,6 +26,7 @@
 
 extern const base::Feature kNewOmniboxAnswerTypes;
 extern const base::Feature kOmniboxEntitySuggestions;
+extern const base::Feature kOmniboxTailSuggestions;
 extern const base::Feature kEnableClipboardProvider;
 extern const base::Feature kSearchProviderWarmUpOnFocus;
 extern const base::Feature kSearchProviderContextAllowHttpsUrls;
diff --git a/components/payments/content/payment_request_state.cc b/components/payments/content/payment_request_state.cc
index 350cccf..28fa65dd 100644
--- a/components/payments/content/payment_request_state.cc
+++ b/components/payments/content/payment_request_state.cc
@@ -319,6 +319,9 @@
   if (!profile_comparator()->IsShippingComplete(selected_shipping_profile_))
     return false;
 
+  if (spec_->request_shipping() && !spec_->selected_shipping_option())
+    return false;
+
   return profile_comparator()->IsContactInfoComplete(selected_contact_profile_);
 }
 
diff --git a/components/payments/content/payment_request_state_unittest.cc b/components/payments/content/payment_request_state_unittest.cc
index d882d84e..186fca9 100644
--- a/components/payments/content/payment_request_state_unittest.cc
+++ b/components/payments/content/payment_request_state_unittest.cc
@@ -227,6 +227,16 @@
   // Simulate that the merchant has validated the shipping address change.
   spec()->UpdateWith(CreateDefaultDetails());
   EXPECT_EQ(2, num_on_selected_information_changed_called());
+
+  // Not ready to pay since there's no selected shipping option.
+  EXPECT_FALSE(state()->is_ready_to_pay());
+
+  // Simulate that the website validates the shipping option.
+  state()->SetSelectedShippingOption("option:1");
+  auto details = CreateDefaultDetails();
+  details->shipping_options[0]->selected = true;
+  spec()->UpdateWith(std::move(details));
+  EXPECT_EQ(3, num_on_selected_information_changed_called());
   EXPECT_TRUE(state()->is_ready_to_pay());
 }
 
@@ -296,7 +306,8 @@
   // Simulate that the merchant has validated the shipping address change.
   spec()->UpdateWith(CreateDefaultDetails());
   EXPECT_EQ(2, num_on_selected_information_changed_called());
-  EXPECT_TRUE(state()->is_ready_to_pay());
+  // Not ready to pay because there's no selected shipping option.
+  EXPECT_FALSE(state()->is_ready_to_pay());
 
   // Check that all the expected values were set for the shipping address.
   EXPECT_EQ("US", selected_shipping_address()->country);
diff --git a/components/safe_browsing_db/database_manager.h b/components/safe_browsing_db/database_manager.h
index 01ae7ca..f566199 100644
--- a/components/safe_browsing_db/database_manager.h
+++ b/components/safe_browsing_db/database_manager.h
@@ -27,6 +27,14 @@
 
 namespace safe_browsing {
 
+// Value returned by some Check*Whitelist() calls that may or may not have an
+// immediate answer.
+enum class AsyncMatch {
+  ASYNC,     // No answer yet -- Client will get a callback
+  MATCH,     // URL matches the list.  No callback.
+  NO_MATCH,  // URL doesn't match. No callback.
+};
+
 struct V4ProtocolConfig;
 class V4GetHashProtocolManager;
 
@@ -64,6 +72,10 @@
     virtual void OnCheckResourceUrlResult(const GURL& url,
                                           SBThreatType threat_type,
                                           const std::string& threat_hash) {}
+
+    // Called when the result of checking a whitelist is known.
+    // Currently only used for CSD whitelist.
+    virtual void OnCheckWhitelistUrlResult(bool is_whitelisted) {}
   };
 
   //
@@ -112,20 +124,17 @@
   // and "client" is called asynchronously with the result when it is ready.
   virtual bool CheckApiBlacklistUrl(const GURL& url, Client* client);
 
+  // Check if the |url| matches any of the full-length hashes from the client-
+  // side phishing detection whitelist. The 3-state return value indicates
+  // the result or that the Client will get a callback later with the result.
+  virtual AsyncMatch CheckCsdWhitelistUrl(const GURL& url, Client* client) = 0;
+
   // Called on the IO thread to check if the given url is safe or not.  If we
   // can synchronously determine that the url is safe, CheckUrl returns true.
   // Otherwise it returns false, and "client" is called asynchronously with the
   // result when it is ready.
   virtual bool CheckBrowseUrl(const GURL& url, Client* client) = 0;
 
-  // Called on the IO thread to check if the given url belongs to the
-  // subresource filter list. If the url doesn't belong to the list, the check
-  // happens synchronously, otherwise it returns false, and "client" is called
-  // asynchronously with the result when it is ready.
-  // Currently supported only on desktop. Returns TRUE if the list is not yet
-  // available.
-  virtual bool CheckUrlForSubresourceFilter(const GURL& url,
-                                            Client* client) = 0;
 
   // Check if the prefix for |url| is in safebrowsing download add lists.
   // Result will be passed to callback in |client|.
@@ -143,15 +152,25 @@
   // to callback in |client|.
   virtual bool CheckResourceUrl(const GURL& url, Client* client) = 0;
 
+  // Called on the IO thread to check if the given url belongs to the
+  // subresource filter list. If the url doesn't belong to the list, the check
+  // happens synchronously, otherwise it returns false, and "client" is called
+  // asynchronously with the result when it is ready.
+  // Currently supported only on desktop. Returns TRUE if the list is not yet
+  // available.
+  virtual bool CheckUrlForSubresourceFilter(const GURL& url,
+                                            Client* client) = 0;
+
   //
-  // Methods to synchronously check whether a URL, or full hash, or IP address
-  // or a DLL file is safe.
+  // Match*(): Methods to synchronously check if various types are safe.
   //
 
   // Check if the |url| matches any of the full-length hashes from the client-
   // side phishing detection whitelist.  Returns true if there was a match and
   // false otherwise.  To make sure we are conservative we will return true if
   // an error occurs.  This method must be called on the IO thread.
+  //
+  // DEPRECATED. ref: http://crbug.com/714300
   virtual bool MatchCsdWhitelistUrl(const GURL& url) = 0;
 
   // Check if |str| matches any of the full-length hashes from the download
diff --git a/components/safe_browsing_db/remote_database_manager.cc b/components/safe_browsing_db/remote_database_manager.cc
index b620426..6b78c53 100644
--- a/components/safe_browsing_db/remote_database_manager.cc
+++ b/components/safe_browsing_db/remote_database_manager.cc
@@ -258,6 +258,13 @@
   return false;
 }
 
+AsyncMatch RemoteSafeBrowsingDatabaseManager::CheckCsdWhitelistUrl(
+    const GURL& url,
+    Client* client) {
+  NOTREACHED();
+  return AsyncMatch::MATCH;
+}
+
 bool RemoteSafeBrowsingDatabaseManager::MatchCsdWhitelistUrl(const GURL& url) {
   NOTREACHED();
   return true;
diff --git a/components/safe_browsing_db/remote_database_manager.h b/components/safe_browsing_db/remote_database_manager.h
index 1f13ca3..eb329f2 100644
--- a/components/safe_browsing_db/remote_database_manager.h
+++ b/components/safe_browsing_db/remote_database_manager.h
@@ -48,6 +48,7 @@
                         Client* client) override;
   bool CheckExtensionIDs(const std::set<std::string>& extension_ids,
                          Client* client) override;
+  AsyncMatch CheckCsdWhitelistUrl(const GURL& url, Client* client) override;
   bool CheckResourceUrl(const GURL& url, Client* client) override;
   bool CheckUrlForSubresourceFilter(const GURL& url, Client* client) override;
   bool MatchCsdWhitelistUrl(const GURL& url) override;
diff --git a/components/safe_browsing_db/test_database_manager.cc b/components/safe_browsing_db/test_database_manager.cc
index 423097e..cdca0b0 100644
--- a/components/safe_browsing_db/test_database_manager.cc
+++ b/components/safe_browsing_db/test_database_manager.cc
@@ -66,6 +66,13 @@
   return true;
 }
 
+AsyncMatch TestSafeBrowsingDatabaseManager::CheckCsdWhitelistUrl(
+    const GURL& url,
+    Client* client) {
+  NOTIMPLEMENTED();
+  return AsyncMatch::MATCH;
+}
+
 bool TestSafeBrowsingDatabaseManager::MatchCsdWhitelistUrl(const GURL& url) {
   NOTIMPLEMENTED();
   return true;
diff --git a/components/safe_browsing_db/test_database_manager.h b/components/safe_browsing_db/test_database_manager.h
index c2cd803f..180723f0 100644
--- a/components/safe_browsing_db/test_database_manager.h
+++ b/components/safe_browsing_db/test_database_manager.h
@@ -26,6 +26,7 @@
   bool CanCheckUrl(const GURL& url) const override;
   bool ChecksAreAlwaysAsync() const override;
   bool CheckBrowseUrl(const GURL& url, Client* client) override;
+  AsyncMatch CheckCsdWhitelistUrl(const GURL& url, Client* client) override;
   bool CheckDownloadUrl(const std::vector<GURL>& url_chain,
                         Client* client) override;
   bool CheckExtensionIDs(const std::set<std::string>& extension_ids,
diff --git a/components/safe_browsing_db/v4_local_database_manager.cc b/components/safe_browsing_db/v4_local_database_manager.cc
index 02617ce..3b37d7b5 100644
--- a/components/safe_browsing_db/v4_local_database_manager.cc
+++ b/components/safe_browsing_db/v4_local_database_manager.cc
@@ -59,7 +59,7 @@
       ListInfo(kSyncOnlyOnChromeBuilds, "UrlCsdDownloadWhitelist.store",
                GetUrlCsdDownloadWhitelistId(), SB_THREAT_TYPE_UNUSED),
       ListInfo(kSyncOnlyOnChromeBuilds, "UrlCsdWhitelist.store",
-               GetUrlCsdWhitelistId(), SB_THREAT_TYPE_UNUSED),
+               GetUrlCsdWhitelistId(), SB_THREAT_TYPE_CSD_WHITELIST),
       ListInfo(kSyncAlways, "UrlSoceng.store", GetUrlSocEngId(),
                SB_THREAT_TYPE_URL_PHISHING),
       ListInfo(kSyncAlways, "UrlMalware.store", GetUrlMalwareId(),
@@ -96,6 +96,8 @@
     case CLIENT_INCIDENT:
     case SUBRESOURCE_FILTER:
       return 2;
+    case CSD_WHITELIST:
+      return 3;
     default:
       NOTREACHED() << "Unexpected ThreatType encountered: "
                    << list_id.threat_type();
@@ -289,15 +291,34 @@
   return HandleCheck(std::move(check));
 }
 
+AsyncMatch V4LocalDatabaseManager::CheckCsdWhitelistUrl(const GURL& url,
+                                                        Client* client) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  StoresToCheck stores_to_check({GetUrlCsdWhitelistId()});
+  if (!AreAllStoresAvailableNow(stores_to_check) || !CanCheckUrl(url)) {
+    // Fail open: Whitelist everything. Otherwise we may run the
+    // CSD phishing/malware detector on popular domains and generate
+    // undue load on the client and server, or send Password Reputation
+    // requests on popular sites. This has the effect of disabling
+    // CSD phishing/malware detection and password reputation service
+    // until the store is first synced and/or loaded from disk.
+    return AsyncMatch::MATCH;
+  }
+
+  std::unique_ptr<PendingCheck> check = base::MakeUnique<PendingCheck>(
+      client, ClientCallbackType::CHECK_CSD_WHITELIST, stores_to_check,
+      std::vector<GURL>(1, url));
+
+  return HandleWhitelistCheck(std::move(check));
+}
+
 bool V4LocalDatabaseManager::MatchCsdWhitelistUrl(const GURL& url) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   StoresToCheck stores_to_check({GetUrlCsdWhitelistId()});
   if (!AreAllStoresAvailableNow(stores_to_check)) {
-    // Fail open: Whitelist everything. Otherwise we may run the
-    // CSD phishing/malware detector on popular domains and generate
-    // undue load on the client and server. This has the effect of disabling
-    // CSD phishing/malware detection until the store is first synced.
+    // Fail open: Whitelist everything. See CheckCsdWhitelistUrl.
     return true;
   }
 
@@ -554,6 +575,34 @@
   return it->sb_threat_type();
 }
 
+AsyncMatch V4LocalDatabaseManager::HandleWhitelistCheck(
+    std::unique_ptr<PendingCheck> check) {
+  // We don't bother queuing whitelist checks since the DB will
+  // normally be available already -- whitelists are used after page load,
+  // and navigations are blocked until the DB is ready and dequeues checks.
+  // The caller should have already checked that the DB is ready.
+  DCHECK(v4_database_);
+
+  FullHashToStoreAndHashPrefixesMap full_hash_to_store_and_hash_prefixes;
+  if (!GetPrefixMatches(check, &full_hash_to_store_and_hash_prefixes)) {
+    return AsyncMatch::NO_MATCH;
+  }
+
+  // Look for any full-length hash in the matches. If there is one,
+  // there's no need for a full-hash check. This saves bandwidth for
+  // very popular sites since they'll have full-length hashes locally.
+  // These loops will have exactly 1 entry most of the time.
+  for (const auto& entry : full_hash_to_store_and_hash_prefixes) {
+    for (const auto& store_and_prefix : entry.second) {
+      if (store_and_prefix.hash_prefix.size() == kMaxHashPrefixLength)
+        return AsyncMatch::MATCH;
+    }
+  }
+
+  ScheduleFullHashCheck(std::move(check), full_hash_to_store_and_hash_prefixes);
+  return AsyncMatch::ASYNC;
+}
+
 bool V4LocalDatabaseManager::HandleCheck(std::unique_ptr<PendingCheck> check) {
   if (!v4_database_) {
     queued_checks_.push_back(std::move(check));
@@ -565,6 +614,14 @@
     return true;
   }
 
+  ScheduleFullHashCheck(std::move(check), full_hash_to_store_and_hash_prefixes);
+  return false;
+}
+
+void V4LocalDatabaseManager::ScheduleFullHashCheck(
+    std::unique_ptr<PendingCheck> check,
+    const FullHashToStoreAndHashPrefixesMap&
+        full_hash_to_store_and_hash_prefixes) {
   // Add check to pending_checks_ before scheduling PerformFullHashCheck so that
   // even if the client calls CancelCheck before PerformFullHashCheck gets
   // called, the check can be found in pending_checks_.
@@ -576,8 +633,6 @@
       base::Bind(&V4LocalDatabaseManager::PerformFullHashCheck,
                  weak_factory_.GetWeakPtr(), base::Passed(std::move(check)),
                  full_hash_to_store_and_hash_prefixes));
-
-  return false;
 }
 
 bool V4LocalDatabaseManager::HandleHashSynchronously(
@@ -700,6 +755,16 @@
                                               check->matching_full_hash);
       break;
 
+    case ClientCallbackType::CHECK_CSD_WHITELIST: {
+      DCHECK_EQ(1u, check->urls.size());
+      bool did_match_whitelist =
+          check->most_severe_threat_type == SB_THREAT_TYPE_CSD_WHITELIST;
+      DCHECK(did_match_whitelist ||
+             check->most_severe_threat_type == SB_THREAT_TYPE_SAFE);
+      check->client->OnCheckWhitelistUrlResult(did_match_whitelist);
+      break;
+    }
+
     case ClientCallbackType::CHECK_EXTENSION_IDS: {
       DCHECK_EQ(check->full_hash_threat_types.size(),
                 check->full_hashes.size());
diff --git a/components/safe_browsing_db/v4_local_database_manager.h b/components/safe_browsing_db/v4_local_database_manager.h
index 9e3ea4fa..0c154325 100644
--- a/components/safe_browsing_db/v4_local_database_manager.h
+++ b/components/safe_browsing_db/v4_local_database_manager.h
@@ -43,6 +43,7 @@
   bool CanCheckUrl(const GURL& url) const override;
   bool ChecksAreAlwaysAsync() const override;
   bool CheckBrowseUrl(const GURL& url, Client* client) override;
+  AsyncMatch CheckCsdWhitelistUrl(const GURL& url, Client* client) override;
   bool CheckDownloadUrl(const std::vector<GURL>& url_chain,
                         Client* client) override;
   // TODO(vakh): |CheckExtensionIDs| in the base class accepts a set of
@@ -88,28 +89,32 @@
   enum class ClientCallbackType {
     // This represents the case when we're trying to determine if a URL is
     // unsafe from the following perspectives: Malware, Phishing, UwS.
-    CHECK_BROWSE_URL = 0,
+    CHECK_BROWSE_URL,
 
     // This represents the case when we're trying to determine if any of the
     // URLs in a vector of URLs is unsafe for downloading binaries.
-    CHECK_DOWNLOAD_URLS = 1,
+    CHECK_DOWNLOAD_URLS,
 
     // This represents the case when we're trying to determine if a URL is an
     // unsafe resource.
-    CHECK_RESOURCE_URL = 2,
+    CHECK_RESOURCE_URL,
 
     // This represents the case when we're trying to determine if a Chrome
     // extension is a unsafe.
-    CHECK_EXTENSION_IDS = 3,
+    CHECK_EXTENSION_IDS,
 
     // This respresents the case when we're trying to determine if a URL belongs
     // to the list where subresource filter should be active.
-    CHECK_URL_FOR_SUBRESOURCE_FILTER = 4,
+    CHECK_URL_FOR_SUBRESOURCE_FILTER,
+
+    // This respresents the case when we're trying to determine if a URL is
+    // part of the CSD whitelist.
+    CHECK_CSD_WHITELIST,
 
     // This represents the other cases when a check is being performed
     // synchronously so a client callback isn't required. For instance, when
     // trying to determing if an IP address is unsafe due to hosting Malware.
-    CHECK_OTHER = 5,
+    CHECK_OTHER,
   };
 
   // The information we need to process a URL safety reputation request and
@@ -221,6 +226,15 @@
   // schedules a task to perform full hash check and returns false.
   bool HandleCheck(std::unique_ptr<PendingCheck> check);
 
+  // Like HandleCheck, but for whitelists that have both full-hashes and
+  // partial hashes in the DB. Returns MATCH, NO_MATCH, or ASYNC.
+  AsyncMatch HandleWhitelistCheck(std::unique_ptr<PendingCheck> check);
+
+  // Schedules a full-hash check for a given set of prefixes.
+  void ScheduleFullHashCheck(std::unique_ptr<PendingCheck> check,
+                             const FullHashToStoreAndHashPrefixesMap&
+                                 full_hash_to_store_and_hash_prefixes);
+
   // Checks |stores_to_check| in database synchronously for hash prefixes
   // matching |hash|. Returns true if there's a match; false otherwise. This is
   // used for lists that have full hash information in the database.
diff --git a/components/safe_browsing_db/v4_local_database_manager_unittest.cc b/components/safe_browsing_db/v4_local_database_manager_unittest.cc
index 34cb4ac5..5e20cb7 100644
--- a/components/safe_browsing_db/v4_local_database_manager_unittest.cc
+++ b/components/safe_browsing_db/v4_local_database_manager_unittest.cc
@@ -31,7 +31,7 @@
   return full_hashes[0];
 }
 
-// Always returns misses from GetFullHashes().
+// Use this if you want GetFullHashes() to always return prescribed results.
 class FakeGetHashProtocolManager : public V4GetHashProtocolManager {
  public:
   FakeGetHashProtocolManager(
@@ -74,6 +74,7 @@
 };
 
 // Use FakeGetHashProtocolManagerFactory in scope, then reset.
+// You should make sure the DatabaseManager is created _after_ this.
 class ScopedFakeGetHashProtocolManagerFactory {
  public:
   ScopedFakeGetHashProtocolManagerFactory(
@@ -113,6 +114,8 @@
       StoreAndHashPrefixes* store_and_hash_prefixes) override {
     store_and_hash_prefixes->clear();
     for (const StoreAndHashPrefix& stored_sahp : store_and_hash_prefixes_) {
+      if (stores_to_check.count(stored_sahp.list_id) == 0)
+        continue;
       const PrefixSize& prefix_size = stored_sahp.hash_prefix.size();
       if (!full_hash.compare(0, prefix_size, stored_sahp.hash_prefix)) {
         store_and_hash_prefixes->push_back(stored_sahp);
@@ -159,6 +162,8 @@
   const bool stores_available_;
 };
 
+// TODO(nparker): This might be simpler with a mock and EXPECT calls.
+// That would also catch unexpected calls.
 class TestClient : public SafeBrowsingDatabaseManager::Client {
  public:
   TestClient(SBThreatType sb_threat_type,
@@ -166,17 +171,10 @@
              V4LocalDatabaseManager* manager_to_cancel = nullptr)
       : expected_sb_threat_type(sb_threat_type),
         expected_urls(1, url),
-        on_check_browse_url_result_called_(false),
-        on_check_download_urls_result_called_(false),
-        on_check_resource_url_result_called_(false),
         manager_to_cancel_(manager_to_cancel) {}
 
   TestClient(SBThreatType sb_threat_type, const std::vector<GURL>& url_chain)
-      : expected_sb_threat_type(sb_threat_type),
-        expected_urls(url_chain),
-        on_check_browse_url_result_called_(false),
-        on_check_download_urls_result_called_(false),
-        on_check_resource_url_result_called_(false) {}
+      : expected_sb_threat_type(sb_threat_type), expected_urls(url_chain) {}
 
   void OnCheckBrowseUrlResult(const GURL& url,
                               SBThreatType threat_type,
@@ -197,6 +195,7 @@
     ASSERT_EQ(threat_type == SB_THREAT_TYPE_SAFE, threat_hash.empty());
     on_check_resource_url_result_called_ = true;
   }
+
   void OnCheckDownloadUrlResult(const std::vector<GURL>& url_chain,
                                 SBThreatType threat_type) override {
     ASSERT_EQ(expected_urls, url_chain);
@@ -206,12 +205,26 @@
 
   SBThreatType expected_sb_threat_type;
   std::vector<GURL> expected_urls;
-  bool on_check_browse_url_result_called_;
-  bool on_check_download_urls_result_called_;
-  bool on_check_resource_url_result_called_;
+  bool on_check_browse_url_result_called_ = false;
+  bool on_check_download_urls_result_called_ = false;
+  bool on_check_resource_url_result_called_ = false;
   V4LocalDatabaseManager* manager_to_cancel_;
 };
 
+class TestWhitelistClient : public SafeBrowsingDatabaseManager::Client {
+ public:
+  explicit TestWhitelistClient(bool whitelist_expected)
+      : whitelist_expected_(whitelist_expected) {}
+
+  void OnCheckWhitelistUrlResult(bool is_whitelisted) override {
+    EXPECT_EQ(whitelist_expected_, is_whitelisted);
+    callback_called_ = true;
+  }
+
+  const bool whitelist_expected_;
+  bool callback_called_ = false;
+};
+
 class TestExtensionClient : public SafeBrowsingDatabaseManager::Client {
  public:
   TestExtensionClient(const std::set<FullHash>& expected_bad_crxs)
@@ -229,18 +242,19 @@
 
 class FakeV4LocalDatabaseManager : public V4LocalDatabaseManager {
  public:
-  void PerformFullHashCheck(std::unique_ptr<PendingCheck> check,
-                            const FullHashToStoreAndHashPrefixesMap&
-                                full_hash_to_store_and_hash_prefixes) override {
-    perform_full_hash_check_called_ = true;
-  }
-
   FakeV4LocalDatabaseManager(
       const base::FilePath& base_path,
       ExtendedReportingLevelCallback extended_reporting_level_callback)
       : V4LocalDatabaseManager(base_path, extended_reporting_level_callback),
         perform_full_hash_check_called_(false) {}
 
+  // V4LocalDatabaseManager impl:
+  void PerformFullHashCheck(std::unique_ptr<PendingCheck> check,
+                            const FullHashToStoreAndHashPrefixesMap&
+                                full_hash_to_store_and_hash_prefixes) override {
+    perform_full_hash_check_called_ = true;
+  }
+
   static bool PerformFullHashCheckCalled(
       scoped_refptr<safe_browsing::V4LocalDatabaseManager>& v4_ldbm) {
     FakeV4LocalDatabaseManager* fake =
@@ -426,6 +440,127 @@
   WaitForTasksOnTaskRunner();
 }
 
+TEST_F(V4LocalDatabaseManagerTest, TestCheckCsdWhitelistWithPrefixMatch) {
+  // Setup to receive full-hash misses. We won't make URL requests.
+  ScopedFakeGetHashProtocolManagerFactory pin(FullHashInfos({}));
+  ResetLocalDatabaseManager();
+  WaitForTasksOnTaskRunner();
+
+  std::string url_white_no_scheme("example.com/white/");
+  FullHash white_full_hash(crypto::SHA256HashString(url_white_no_scheme));
+  const HashPrefix white_hash_prefix(white_full_hash.substr(0, 5));
+  StoreAndHashPrefixes store_and_hash_prefixes;
+  store_and_hash_prefixes.emplace_back(GetUrlCsdWhitelistId(),
+                                       white_hash_prefix);
+  ReplaceV4Database(store_and_hash_prefixes, true /* stores_available */);
+
+  TestWhitelistClient client(false /* whitelist_expected */);
+  const GURL url_check("https://" + url_white_no_scheme);
+  EXPECT_EQ(AsyncMatch::ASYNC, v4_local_database_manager_->CheckCsdWhitelistUrl(
+                                   url_check, &client));
+
+  EXPECT_FALSE(client.callback_called_);
+
+  // Wait for PerformFullHashCheck to complete.
+  WaitForTasksOnTaskRunner();
+  EXPECT_TRUE(client.callback_called_);
+}
+
+// This is like CsdWhitelistWithPrefixMatch, but we also verify the
+// full-hash-match results in an appropriate callback value.
+TEST_F(V4LocalDatabaseManagerTest,
+       TestCheckCsdWhitelistWithPrefixTheFullMatch) {
+  std::string url_white_no_scheme("example.com/white/");
+  FullHash white_full_hash(crypto::SHA256HashString(url_white_no_scheme));
+
+  // Setup to receive full-hash hit. We won't make URL requests.
+  FullHashInfos infos(
+      {{white_full_hash, GetUrlCsdWhitelistId(), base::Time::Now()}});
+  ScopedFakeGetHashProtocolManagerFactory pin(infos);
+  ResetLocalDatabaseManager();
+  WaitForTasksOnTaskRunner();
+
+  const HashPrefix white_hash_prefix(white_full_hash.substr(0, 5));
+  StoreAndHashPrefixes store_and_hash_prefixes;
+  store_and_hash_prefixes.emplace_back(GetUrlCsdWhitelistId(),
+                                       white_hash_prefix);
+  ReplaceV4Database(store_and_hash_prefixes, true /* stores_available */);
+
+  TestWhitelistClient client(true /* whitelist_expected */);
+  const GURL url_check("https://" + url_white_no_scheme);
+  EXPECT_EQ(AsyncMatch::ASYNC, v4_local_database_manager_->CheckCsdWhitelistUrl(
+                                   url_check, &client));
+
+  EXPECT_FALSE(client.callback_called_);
+
+  // Wait for PerformFullHashCheck to complete.
+  WaitForTasksOnTaskRunner();
+  EXPECT_TRUE(client.callback_called_);
+}
+
+TEST_F(V4LocalDatabaseManagerTest, TestCheckCsdWhitelistWithFullMatch) {
+  // Setup to receive full-hash misses. We won't make URL requests.
+  ScopedFakeGetHashProtocolManagerFactory pin(FullHashInfos({}));
+  ResetLocalDatabaseManager();
+  WaitForTasksOnTaskRunner();
+
+  std::string url_white_no_scheme("example.com/white/");
+  FullHash white_full_hash(crypto::SHA256HashString(url_white_no_scheme));
+  StoreAndHashPrefixes store_and_hash_prefixes;
+  store_and_hash_prefixes.emplace_back(GetUrlCsdWhitelistId(), white_full_hash);
+  ReplaceV4Database(store_and_hash_prefixes, true /* stores_available */);
+
+  TestWhitelistClient client(false /* whitelist_expected */);
+  const GURL url_check("https://" + url_white_no_scheme);
+  EXPECT_EQ(AsyncMatch::MATCH, v4_local_database_manager_->CheckCsdWhitelistUrl(
+                                   url_check, &client));
+
+  WaitForTasksOnTaskRunner();
+  EXPECT_FALSE(client.callback_called_);
+}
+
+TEST_F(V4LocalDatabaseManagerTest, TestCheckCsdWhitelistWithNoMatch) {
+  // Setup to receive full-hash misses. We won't make URL requests.
+  ScopedFakeGetHashProtocolManagerFactory pin(FullHashInfos({}));
+  ResetLocalDatabaseManager();
+  WaitForTasksOnTaskRunner();
+
+  // Add a full hash that won't match the URL we check.
+  std::string url_white_no_scheme("example.com/white/");
+  FullHash white_full_hash(crypto::SHA256HashString(url_white_no_scheme));
+  StoreAndHashPrefixes store_and_hash_prefixes;
+  store_and_hash_prefixes.emplace_back(GetUrlMalwareId(), white_full_hash);
+  ReplaceV4Database(store_and_hash_prefixes, true /* stores_available */);
+
+  TestWhitelistClient client(true /* whitelist_expected */);
+  const GURL url_check("https://other.com/");
+  EXPECT_EQ(
+      AsyncMatch::NO_MATCH,
+      v4_local_database_manager_->CheckCsdWhitelistUrl(url_check, &client));
+
+  WaitForTasksOnTaskRunner();
+  EXPECT_FALSE(client.callback_called_);
+}
+
+// When whitelist is unavailable, all URLS should be whitelisted.
+TEST_F(V4LocalDatabaseManagerTest, TestCheckCsdWhitelistUnavailable) {
+  // Setup to receive full-hash misses. We won't make URL requests.
+  ScopedFakeGetHashProtocolManagerFactory pin(FullHashInfos({}));
+  ResetLocalDatabaseManager();
+  WaitForTasksOnTaskRunner();
+
+  StoreAndHashPrefixes store_and_hash_prefixes;
+  ReplaceV4Database(store_and_hash_prefixes, false /* stores_available */);
+
+  TestWhitelistClient client(false /* whitelist_expected */);
+  const GURL url_check("https://other.com/");
+  EXPECT_EQ(AsyncMatch::MATCH, v4_local_database_manager_->CheckCsdWhitelistUrl(
+                                   url_check, &client));
+
+  WaitForTasksOnTaskRunner();
+  EXPECT_FALSE(client.callback_called_);
+}
+
 TEST_F(V4LocalDatabaseManagerTest,
        TestCheckBrowseUrlReturnsNoMatchWhenDisabled) {
   WaitForTasksOnTaskRunner();
@@ -671,7 +806,7 @@
   GURL other_url("http://iffy.com");
 
   StoreAndHashPrefixes store_and_hash_prefixes;
-  store_and_hash_prefixes.emplace_back(GetCertCsdDownloadWhitelistId(),
+  store_and_hash_prefixes.emplace_back(GetUrlCsdDownloadWhitelistId(),
                                        HashForUrl(good_url));
 
   ReplaceV4Database(store_and_hash_prefixes, false /* not available */);
diff --git a/components/safe_browsing_db/v4_protocol_manager_util.h b/components/safe_browsing_db/v4_protocol_manager_util.h
index 882fb4a..1619fd5 100644
--- a/components/safe_browsing_db/v4_protocol_manager_util.h
+++ b/components/safe_browsing_db/v4_protocol_manager_util.h
@@ -115,6 +115,9 @@
 
   // Activation patterns for the Subresource Filter.
   SB_THREAT_TYPE_SUBRESOURCE_FILTER,
+
+  // CSD Phishing whitelist.  This "threat" means a URL matched the whitelist.
+  SB_THREAT_TYPE_CSD_WHITELIST,
 };
 
 // The information required to uniquely identify each list the client is
diff --git a/components/signin/core/browser/account_fetcher_service.cc b/components/signin/core/browser/account_fetcher_service.cc
index 7f25b2d..6203942 100644
--- a/components/signin/core/browser/account_fetcher_service.cc
+++ b/components/signin/core/browser/account_fetcher_service.cc
@@ -65,6 +65,7 @@
       child_info_request_(nullptr) {}
 
 AccountFetcherService::~AccountFetcherService() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(shutdown_called_);
 }
 
@@ -142,7 +143,7 @@
 // account. This is possible since we only support a single account to be a
 // child anyway.
 void AccountFetcherService::UpdateChildInfo() {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   std::vector<std::string> accounts = token_service_->GetAccounts();
   if (accounts.size() == 1) {
     const std::string& candidate = accounts[0];
@@ -160,7 +161,7 @@
 }
 
 void AccountFetcherService::MaybeEnableNetworkFetches() {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (!profile_loaded_ || !refresh_tokens_loaded_)
     return;
   if (!network_fetches_enabled_) {
@@ -199,7 +200,7 @@
 // Starts fetching user information. This is called periodically to refresh.
 void AccountFetcherService::StartFetchingUserInfo(
     const std::string& account_id) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(network_fetches_enabled_);
 
   std::unique_ptr<AccountInfoFetcher>& request =
@@ -341,7 +342,7 @@
 }
 
 void AccountFetcherService::OnRefreshTokensLoaded() {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   refresh_tokens_loaded_ = true;
   MaybeEnableNetworkFetches();
 }
diff --git a/components/signin/core/browser/account_fetcher_service.h b/components/signin/core/browser/account_fetcher_service.h
index 5ca34f1f..aefdcdd 100644
--- a/components/signin/core/browser/account_fetcher_service.h
+++ b/components/signin/core/browser/account_fetcher_service.h
@@ -11,7 +11,7 @@
 #include <unordered_map>
 
 #include "base/macros.h"
-#include "base/threading/non_thread_safe.h"
+#include "base/sequence_checker.h"
 #include "base/timer/timer.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "google_apis/gaia/oauth2_token_service.h"
@@ -32,8 +32,7 @@
 }
 
 class AccountFetcherService : public KeyedService,
-                              public OAuth2TokenService::Observer,
-                              public base::NonThreadSafe {
+                              public OAuth2TokenService::Observer {
  public:
   // Name of the preference that tracks the int64_t representation of the last
   // time the AccountTrackerService was updated.
@@ -139,6 +138,8 @@
                      std::unique_ptr<RefreshTokenAnnotationRequest>>
       refresh_token_annotation_requests_;
 
+  SEQUENCE_CHECKER(sequence_checker_);
+
   DISALLOW_COPY_AND_ASSIGN(AccountFetcherService);
 };
 
diff --git a/components/signin/core/browser/account_tracker_service.cc b/components/signin/core/browser/account_tracker_service.cc
index 129b124..dc4dba0 100644
--- a/components/signin/core/browser/account_tracker_service.cc
+++ b/components/signin/core/browser/account_tracker_service.cc
@@ -60,6 +60,7 @@
 AccountTrackerService::AccountTrackerService() : signin_client_(nullptr) {}
 
 AccountTrackerService::~AccountTrackerService() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 }
 
 // static
diff --git a/components/signin/core/browser/account_tracker_service.h b/components/signin/core/browser/account_tracker_service.h
index b92e0a9..cc4035c 100644
--- a/components/signin/core/browser/account_tracker_service.h
+++ b/components/signin/core/browser/account_tracker_service.h
@@ -13,13 +13,12 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/observer_list.h"
-#include "base/threading/non_thread_safe.h"
+#include "base/sequence_checker.h"
 #include "base/timer/timer.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/signin/core/browser/account_info.h"
 #include "google_apis/gaia/gaia_auth_util.h"
 
-
 class PrefService;
 class SigninClient;
 
@@ -33,8 +32,7 @@
 
 // AccountTrackerService is a KeyedService that retrieves and caches GAIA
 // information about Google Accounts.
-class AccountTrackerService : public KeyedService,
-                              public base::NonThreadSafe {
+class AccountTrackerService : public KeyedService {
  public:
   // Name of the preference property that persists the account information
   // tracked by this service.
@@ -157,6 +155,8 @@
   std::map<std::string, AccountState> accounts_;
   base::ObserverList<Observer> observer_list_;
 
+  SEQUENCE_CHECKER(sequence_checker_);
+
   DISALLOW_COPY_AND_ASSIGN(AccountTrackerService);
 };
 
diff --git a/components/signin/core/browser/refresh_token_annotation_request.cc b/components/signin/core/browser/refresh_token_annotation_request.cc
index 191dab8e..d1e11c9 100644
--- a/components/signin/core/browser/refresh_token_annotation_request.cc
+++ b/components/signin/core/browser/refresh_token_annotation_request.cc
@@ -41,7 +41,7 @@
 }
 
 RefreshTokenAnnotationRequest::~RefreshTokenAnnotationRequest() {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 }
 
 // static
@@ -102,7 +102,7 @@
 void RefreshTokenAnnotationRequest::RequestAccessToken(
     OAuth2TokenService* token_service,
     const std::string& account_id) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   OAuth2TokenService::ScopeSet scopes;
   scopes.insert(GaiaConstants::kOAuth1LoginScope);
   access_token_request_ = token_service->StartRequest(account_id, scopes, this);
@@ -112,7 +112,7 @@
     const OAuth2TokenService::Request* request,
     const std::string& access_token,
     const base::Time& expiration_time) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DVLOG(2) << "Got access token";
   Start(request_context_getter_.get(), access_token);
 }
@@ -120,7 +120,7 @@
 void RefreshTokenAnnotationRequest::OnGetTokenFailure(
     const OAuth2TokenService::Request* request,
     const GoogleServiceAuthError& error) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DVLOG(2) << "Failed to get access token";
   RecordRequestStatusHistogram(false);
   base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, request_callback_);
@@ -156,7 +156,7 @@
 
 void RefreshTokenAnnotationRequest::ProcessApiCallSuccess(
     const net::URLFetcher* source) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DVLOG(2) << "Request succeeded";
   RecordRequestStatusHistogram(true);
   base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, request_callback_);
@@ -165,7 +165,7 @@
 
 void RefreshTokenAnnotationRequest::ProcessApiCallFailure(
     const net::URLFetcher* source) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DVLOG(2) << "Request failed";
   RecordRequestStatusHistogram(false);
   base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, request_callback_);
diff --git a/components/signin/core/browser/refresh_token_annotation_request.h b/components/signin/core/browser/refresh_token_annotation_request.h
index 483830b..4965ef8 100644
--- a/components/signin/core/browser/refresh_token_annotation_request.h
+++ b/components/signin/core/browser/refresh_token_annotation_request.h
@@ -10,7 +10,7 @@
 #include "base/callback.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
-#include "base/threading/non_thread_safe.h"
+#include "base/sequence_checker.h"
 #include "google_apis/gaia/oauth2_api_call_flow.h"
 #include "google_apis/gaia/oauth2_token_service.h"
 
@@ -22,8 +22,7 @@
 // important to keep server QPS low therefore this request is sent on average
 // once per 10 days per profile.
 // This code shold be removed once majority of refresh tokens are updated.
-class RefreshTokenAnnotationRequest : public base::NonThreadSafe,
-                                      public OAuth2TokenService::Consumer,
+class RefreshTokenAnnotationRequest : public OAuth2TokenService::Consumer,
                                       public OAuth2ApiCallFlow {
  public:
   ~RefreshTokenAnnotationRequest() override;
@@ -84,6 +83,8 @@
 
   std::unique_ptr<OAuth2TokenService::Request> access_token_request_;
 
+  SEQUENCE_CHECKER(sequence_checker_);
+
   DISALLOW_COPY_AND_ASSIGN(RefreshTokenAnnotationRequest);
 };
 
diff --git a/components/sync/BUILD.gn b/components/sync/BUILD.gn
index 8fa00f3..ae91ee0 100644
--- a/components/sync/BUILD.gn
+++ b/components/sync/BUILD.gn
@@ -572,8 +572,14 @@
     "syncable/write_transaction.h",
     "syncable/write_transaction_info.cc",
     "syncable/write_transaction_info.h",
+    "user_events/fake_user_event_service.cc",
+    "user_events/fake_user_event_service.h",
+    "user_events/no_op_user_event_service.cc",
+    "user_events/no_op_user_event_service.h",
     "user_events/user_event_service.cc",
     "user_events/user_event_service.h",
+    "user_events/user_event_service_impl.cc",
+    "user_events/user_event_service_impl.h",
     "user_events/user_event_sync_bridge.cc",
     "user_events/user_event_sync_bridge.h",
   ]
@@ -945,7 +951,7 @@
     "syncable/syncable_enum_conversions_unittest.cc",
     "syncable/syncable_id_unittest.cc",
     "syncable/syncable_unittest.cc",
-    "user_events/user_event_service_unittest.cc",
+    "user_events/user_event_service_impl_unittest.cc",
     "user_events/user_event_sync_bridge_unittest.cc",
   ]
 
diff --git a/components/sync/user_events/fake_user_event_service.cc b/components/sync/user_events/fake_user_event_service.cc
new file mode 100644
index 0000000..44c842a6
--- /dev/null
+++ b/components/sync/user_events/fake_user_event_service.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 "components/sync/user_events/fake_user_event_service.h"
+
+using sync_pb::UserEventSpecifics;
+
+namespace syncer {
+
+FakeUserEventService::FakeUserEventService() {}
+
+FakeUserEventService::~FakeUserEventService() {}
+
+void FakeUserEventService::RecordUserEvent(
+    std::unique_ptr<UserEventSpecifics> specifics) {
+  DCHECK(specifics);
+  RecordUserEvent(*specifics);
+}
+
+void FakeUserEventService::RecordUserEvent(
+    const UserEventSpecifics& specifics) {
+  recorded_user_events_.push_back(specifics);
+}
+
+base::WeakPtr<ModelTypeSyncBridge> FakeUserEventService::GetSyncBridge() {
+  return base::WeakPtr<ModelTypeSyncBridge>();
+}
+
+void FakeUserEventService::RegisterDependentFieldTrial(
+    const std::string& trial_name,
+    UserEventSpecifics::EventCase event_case) {
+  registered_dependent_field_trials_[trial_name].insert(event_case);
+}
+
+const std::vector<UserEventSpecifics>&
+FakeUserEventService::GetRecordedUserEvents() const {
+  return recorded_user_events_;
+}
+
+const std::map<std::string, std::set<sync_pb::UserEventSpecifics::EventCase>>&
+FakeUserEventService::GetRegisteredDependentFieldTrials() const {
+  return registered_dependent_field_trials_;
+}
+
+}  // namespace syncer
diff --git a/components/sync/user_events/fake_user_event_service.h b/components/sync/user_events/fake_user_event_service.h
new file mode 100644
index 0000000..39399c33
--- /dev/null
+++ b/components/sync/user_events/fake_user_event_service.h
@@ -0,0 +1,53 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SYNC_USER_EVENTS_FAKE_USER_EVENT_SERVICE_H_
+#define COMPONENTS_SYNC_USER_EVENTS_FAKE_USER_EVENT_SERVICE_H_
+
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "components/sync/protocol/user_event_specifics.pb.h"
+#include "components/sync/user_events/user_event_service.h"
+
+namespace syncer {
+
+class ModelTypeSyncBridge;
+
+// This implementation is intended to be used in unit tests, with public
+// accessors that allow reading all data to verify expectations.
+class FakeUserEventService : public UserEventService {
+ public:
+  FakeUserEventService();
+  ~FakeUserEventService() override;
+
+  // UserEventService implementation.
+  void RecordUserEvent(
+      std::unique_ptr<sync_pb::UserEventSpecifics> specifics) override;
+  void RecordUserEvent(const sync_pb::UserEventSpecifics& specifics) override;
+  void RegisterDependentFieldTrial(
+      const std::string& trial_name,
+      sync_pb::UserEventSpecifics::EventCase event_case) override;
+  base::WeakPtr<ModelTypeSyncBridge> GetSyncBridge() override;
+
+  const std::vector<sync_pb::UserEventSpecifics>& GetRecordedUserEvents() const;
+  const std::map<std::string, std::set<sync_pb::UserEventSpecifics::EventCase>>&
+  GetRegisteredDependentFieldTrials() const;
+
+ private:
+  std::vector<sync_pb::UserEventSpecifics> recorded_user_events_;
+  std::map<std::string, std::set<sync_pb::UserEventSpecifics::EventCase>>
+      registered_dependent_field_trials_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeUserEventService);
+};
+
+}  // namespace syncer
+
+#endif  // COMPONENTS_SYNC_USER_EVENTS_FAKE_USER_EVENT_SERVICE_H_
diff --git a/components/sync/user_events/no_op_user_event_service.cc b/components/sync/user_events/no_op_user_event_service.cc
new file mode 100644
index 0000000..cb259cb7
--- /dev/null
+++ b/components/sync/user_events/no_op_user_event_service.cc
@@ -0,0 +1,31 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/sync/user_events/no_op_user_event_service.h"
+
+#include "base/memory/weak_ptr.h"
+
+using sync_pb::UserEventSpecifics;
+
+namespace syncer {
+
+NoOpUserEventService::NoOpUserEventService() {}
+
+NoOpUserEventService::~NoOpUserEventService() {}
+
+void NoOpUserEventService::RecordUserEvent(
+    std::unique_ptr<UserEventSpecifics> specifics) {}
+
+void NoOpUserEventService::RecordUserEvent(
+    const UserEventSpecifics& specifics) {}
+
+base::WeakPtr<ModelTypeSyncBridge> NoOpUserEventService::GetSyncBridge() {
+  return base::WeakPtr<ModelTypeSyncBridge>();
+}
+
+void NoOpUserEventService::RegisterDependentFieldTrial(
+    const std::string& trial_name,
+    UserEventSpecifics::EventCase event_case) {}
+
+}  // namespace syncer
diff --git a/components/sync/user_events/no_op_user_event_service.h b/components/sync/user_events/no_op_user_event_service.h
new file mode 100644
index 0000000..2d69045
--- /dev/null
+++ b/components/sync/user_events/no_op_user_event_service.h
@@ -0,0 +1,40 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SYNC_USER_EVENTS_NO_OP_USER_EVENT_SERVICE_H_
+#define COMPONENTS_SYNC_USER_EVENTS_NO_OP_USER_EVENT_SERVICE_H_
+
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "components/sync/user_events/user_event_service.h"
+
+namespace syncer {
+
+class ModelTypeSyncBridge;
+
+// This implementation is used when we know event should never be recorded,
+// such as in incognito mode.
+class NoOpUserEventService : public UserEventService {
+ public:
+  NoOpUserEventService();
+  ~NoOpUserEventService() override;
+
+  // UserEventService implementation.
+  void RecordUserEvent(
+      std::unique_ptr<sync_pb::UserEventSpecifics> specifics) override;
+  void RecordUserEvent(const sync_pb::UserEventSpecifics& specifics) override;
+  void RegisterDependentFieldTrial(
+      const std::string& trial_name,
+      sync_pb::UserEventSpecifics::EventCase event_case) override;
+  base::WeakPtr<ModelTypeSyncBridge> GetSyncBridge() override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NoOpUserEventService);
+};
+
+}  // namespace syncer
+
+#endif  // COMPONENTS_SYNC_USER_EVENTS_NO_OP_USER_EVENT_SERVICE_H_
diff --git a/components/sync/user_events/user_event_service.cc b/components/sync/user_events/user_event_service.cc
index 7a7e0b8c..31053e5 100644
--- a/components/sync/user_events/user_event_service.cc
+++ b/components/sync/user_events/user_event_service.cc
@@ -4,62 +4,10 @@
 
 #include "components/sync/user_events/user_event_service.h"
 
-#include <utility>
-
-#include "base/bind.h"
-#include "base/feature_list.h"
-#include "base/memory/ptr_util.h"
-#include "base/rand_util.h"
-#include "components/sync/driver/sync_driver_switches.h"
-#include "components/sync/driver/sync_service.h"
-#include "components/sync/model/model_type_sync_bridge.h"
-#include "components/sync/user_events/user_event_sync_bridge.h"
-
-using sync_pb::UserEventSpecifics;
-
 namespace syncer {
 
-UserEventService::UserEventService(SyncService* sync_service,
-                                   std::unique_ptr<UserEventSyncBridge> bridge)
-    : sync_service_(sync_service),
-      bridge_(std::move(bridge)),
-      session_id_(base::RandUint64()) {
-  // TODO(skym): Subscribe to events about field trial membership changing.
-}
+UserEventService::UserEventService() {}
 
 UserEventService::~UserEventService() {}
 
-void UserEventService::Shutdown() {}
-
-void UserEventService::RecordUserEvent(
-    std::unique_ptr<UserEventSpecifics> specifics) {
-  if (CanRecordEvent(*specifics)) {
-    DCHECK(!specifics->has_session_id());
-    specifics->set_session_id(session_id_);
-    bridge_->RecordUserEvent(std::move(specifics));
-  }
-}
-
-void UserEventService::RecordUserEvent(const UserEventSpecifics& specifics) {
-  RecordUserEvent(base::MakeUnique<UserEventSpecifics>(specifics));
-}
-
-base::WeakPtr<ModelTypeSyncBridge> UserEventService::GetSyncBridge() {
-  return bridge_->AsWeakPtr();
-}
-
-bool UserEventService::CanRecordEvent(const UserEventSpecifics& specifics) {
-  // We only record events if the user is syncing history and has not enabled
-  // a custom passphrase. The type HISTORY_DELETE_DIRECTIVES is enabled in and
-  // only in this exact scenario.
-  return base::FeatureList::IsEnabled(switches::kSyncUserEvents) &&
-         sync_service_ != nullptr && sync_service_->IsEngineInitialized() &&
-         sync_service_->GetPreferredDataTypes().Has(HISTORY_DELETE_DIRECTIVES);
-}
-
-void RegisterDependentFieldTrial(const std::string& trial_name,
-                                 UserEventSpecifics::EventCase event_case) {
-  // TODO(skym): Implementation.
-}
-
 }  // namespace syncer
diff --git a/components/sync/user_events/user_event_service.h b/components/sync/user_events/user_event_service.h
index 09e2b60..0e7841d 100644
--- a/components/sync/user_events/user_event_service.h
+++ b/components/sync/user_events/user_event_service.h
@@ -16,45 +16,30 @@
 namespace syncer {
 
 class ModelTypeSyncBridge;
-class SyncService;
-class UserEventSyncBridge;
 
 class UserEventService : public KeyedService {
  public:
-  UserEventService(SyncService* sync_service,
-                   std::unique_ptr<UserEventSyncBridge> bridge);
-
+  UserEventService();
   ~UserEventService() override;
 
-  // KeyedService implementation
-  void Shutdown() override;
-
   // Records a given event to be reported. Relevant settings will be checked to
   // verify user events should be emitted and this will no-op if the the
   // requisite permissions are not present.
-  void RecordUserEvent(std::unique_ptr<sync_pb::UserEventSpecifics> specifics);
-  void RecordUserEvent(const sync_pb::UserEventSpecifics& specifics);
+  virtual void RecordUserEvent(
+      std::unique_ptr<sync_pb::UserEventSpecifics> specifics) = 0;
+  virtual void RecordUserEvent(
+      const sync_pb::UserEventSpecifics& specifics) = 0;
 
   // Register that knowledge about a given field trial is important when
   // interpreting specified user event type, and should be recorded if assigned.
-  void RegisterDependentFieldTrial(
+  virtual void RegisterDependentFieldTrial(
       const std::string& trial_name,
-      sync_pb::UserEventSpecifics::EventCase event_case);
+      sync_pb::UserEventSpecifics::EventCase event_case) = 0;
 
-  base::WeakPtr<ModelTypeSyncBridge> GetSyncBridge();
+  // Returns the underlying Sync integration point.
+  virtual base::WeakPtr<ModelTypeSyncBridge> GetSyncBridge() = 0;
 
  private:
-  bool CanRecordEvent(const sync_pb::UserEventSpecifics& specifics);
-
-  SyncService* sync_service_;
-
-  std::unique_ptr<UserEventSyncBridge> bridge_;
-
-  // Holds onto a random number for the duration of this execution of chrome. On
-  // restart it will be regenerated. This can be attached to events to know
-  // which events came from the same session.
-  uint64_t session_id_;
-
   DISALLOW_COPY_AND_ASSIGN(UserEventService);
 };
 
diff --git a/components/sync/user_events/user_event_service_impl.cc b/components/sync/user_events/user_event_service_impl.cc
new file mode 100644
index 0000000..b516241
--- /dev/null
+++ b/components/sync/user_events/user_event_service_impl.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 "components/sync/user_events/user_event_service_impl.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/feature_list.h"
+#include "base/memory/ptr_util.h"
+#include "base/rand_util.h"
+#include "components/sync/driver/sync_driver_switches.h"
+#include "components/sync/driver/sync_service.h"
+#include "components/sync/model/model_type_sync_bridge.h"
+#include "components/sync/user_events/user_event_sync_bridge.h"
+
+using sync_pb::UserEventSpecifics;
+
+namespace syncer {
+
+UserEventServiceImpl::UserEventServiceImpl(
+    SyncService* sync_service,
+    std::unique_ptr<UserEventSyncBridge> bridge)
+    : sync_service_(sync_service),
+      bridge_(std::move(bridge)),
+      session_id_(base::RandUint64()) {
+  // TODO(skym): Subscribe to events about field trial membership changing.
+}
+
+UserEventServiceImpl::~UserEventServiceImpl() {}
+
+void UserEventServiceImpl::Shutdown() {}
+
+void UserEventServiceImpl::RecordUserEvent(
+    std::unique_ptr<UserEventSpecifics> specifics) {
+  if (ShouldRecordEvent(*specifics)) {
+    DCHECK(!specifics->has_session_id());
+    specifics->set_session_id(session_id_);
+    bridge_->RecordUserEvent(std::move(specifics));
+  }
+}
+
+void UserEventServiceImpl::RecordUserEvent(
+    const UserEventSpecifics& specifics) {
+  RecordUserEvent(base::MakeUnique<UserEventSpecifics>(specifics));
+}
+
+base::WeakPtr<ModelTypeSyncBridge> UserEventServiceImpl::GetSyncBridge() {
+  return bridge_->AsWeakPtr();
+}
+
+bool UserEventServiceImpl::ShouldRecordEvent(
+    const UserEventSpecifics& specifics) {
+  // We only record events if the user is syncing history and has not enabled
+  // a custom passphrase. The type HISTORY_DELETE_DIRECTIVES is enabled in and
+  // only in this exact scenario.
+  return base::FeatureList::IsEnabled(switches::kSyncUserEvents) &&
+         sync_service_ != nullptr && sync_service_->IsEngineInitialized() &&
+         sync_service_->GetPreferredDataTypes().Has(HISTORY_DELETE_DIRECTIVES);
+}
+
+void UserEventServiceImpl::RegisterDependentFieldTrial(
+    const std::string& trial_name,
+    UserEventSpecifics::EventCase event_case) {
+  // TODO(skym): Implementation.
+}
+
+}  // namespace syncer
diff --git a/components/sync/user_events/user_event_service_impl.h b/components/sync/user_events/user_event_service_impl.h
new file mode 100644
index 0000000..578543f9
--- /dev/null
+++ b/components/sync/user_events/user_event_service_impl.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 COMPONENTS_SYNC_USER_EVENTS_USER_EVENT_SERVICE_IMPL_H_
+#define COMPONENTS_SYNC_USER_EVENTS_USER_EVENT_SERVICE_IMPL_H_
+
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/sync/protocol/user_event_specifics.pb.h"
+#include "components/sync/user_events/user_event_service.h"
+
+namespace syncer {
+
+class ModelTypeSyncBridge;
+class SyncService;
+class UserEventSyncBridge;
+
+class UserEventServiceImpl : public UserEventService {
+ public:
+  UserEventServiceImpl(SyncService* sync_service,
+                       std::unique_ptr<UserEventSyncBridge> bridge);
+  ~UserEventServiceImpl() override;
+
+  // KeyedService implementation.
+  void Shutdown() override;
+
+  // UserEventService implementation.
+  void RecordUserEvent(
+      std::unique_ptr<sync_pb::UserEventSpecifics> specifics) override;
+  void RecordUserEvent(const sync_pb::UserEventSpecifics& specifics) override;
+  void RegisterDependentFieldTrial(
+      const std::string& trial_name,
+      sync_pb::UserEventSpecifics::EventCase event_case) override;
+  base::WeakPtr<ModelTypeSyncBridge> GetSyncBridge() override;
+
+ private:
+  bool ShouldRecordEvent(const sync_pb::UserEventSpecifics& specifics);
+
+  SyncService* sync_service_;
+
+  std::unique_ptr<UserEventSyncBridge> bridge_;
+
+  // Holds onto a random number for the duration of this execution of chrome. On
+  // restart it will be regenerated. This can be attached to events to know
+  // which events came from the same session.
+  uint64_t session_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(UserEventServiceImpl);
+};
+
+}  // namespace syncer
+
+#endif  // COMPONENTS_SYNC_USER_EVENTS_USER_EVENT_SERVICE_IMPL_H_
diff --git a/components/sync/user_events/user_event_service_unittest.cc b/components/sync/user_events/user_event_service_impl_unittest.cc
similarity index 80%
rename from components/sync/user_events/user_event_service_unittest.cc
rename to components/sync/user_events/user_event_service_impl_unittest.cc
index f7862e6..d6f4279 100644
--- a/components/sync/user_events/user_event_service_unittest.cc
+++ b/components/sync/user_events/user_event_service_impl_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/sync/user_events/user_event_service.h"
+#include "components/sync/user_events/user_event_service_impl.h"
 
 #include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
@@ -39,9 +39,9 @@
   ModelTypeSet preferred_data_types_;
 };
 
-class UserEventServiceTest : public testing::Test {
+class UserEventServiceImplTest : public testing::Test {
  protected:
-  UserEventServiceTest() {
+  UserEventServiceImplTest() {
     scoped_feature_list_ = base::MakeUnique<base::test::ScopedFeatureList>();
     scoped_feature_list_->InitAndEnableFeature(switches::kSyncUserEvents);
   }
@@ -65,51 +65,51 @@
   base::MessageLoop message_loop_;
 };
 
-TEST_F(UserEventServiceTest, ShouldNotRecordNoSync) {
-  UserEventService service(nullptr, MakeBridge());
+TEST_F(UserEventServiceImplTest, ShouldNotRecordNoSync) {
+  UserEventServiceImpl service(nullptr, MakeBridge());
   service.RecordUserEvent(base::MakeUnique<UserEventSpecifics>());
   EXPECT_EQ(0u, processor().put_multimap().size());
 }
 
-TEST_F(UserEventServiceTest, ShouldNotRecordFeatureIsDisabled) {
+TEST_F(UserEventServiceImplTest, ShouldNotRecordFeatureIsDisabled) {
   DisableUserEvents();
   TestSyncService sync_service(false, ModelTypeSet(HISTORY_DELETE_DIRECTIVES));
-  UserEventService service(&sync_service, MakeBridge());
+  UserEventServiceImpl service(&sync_service, MakeBridge());
   service.RecordUserEvent(base::MakeUnique<UserEventSpecifics>());
   EXPECT_EQ(0u, processor().put_multimap().size());
 }
 
-TEST_F(UserEventServiceTest, ShouldNotRecordNoHistory) {
+TEST_F(UserEventServiceImplTest, ShouldNotRecordNoHistory) {
   TestSyncService sync_service(true, ModelTypeSet());
-  UserEventService service(&sync_service, MakeBridge());
+  UserEventServiceImpl service(&sync_service, MakeBridge());
   service.RecordUserEvent(base::MakeUnique<UserEventSpecifics>());
   EXPECT_EQ(0u, processor().put_multimap().size());
 }
 
-TEST_F(UserEventServiceTest, ShouldNotRecordEngineOff) {
+TEST_F(UserEventServiceImplTest, ShouldNotRecordEngineOff) {
   TestSyncService sync_service(false, ModelTypeSet(HISTORY_DELETE_DIRECTIVES));
-  UserEventService service(&sync_service, MakeBridge());
+  UserEventServiceImpl service(&sync_service, MakeBridge());
   service.RecordUserEvent(base::MakeUnique<UserEventSpecifics>());
   EXPECT_EQ(0u, processor().put_multimap().size());
 }
 
-TEST_F(UserEventServiceTest, ShouldRecord) {
+TEST_F(UserEventServiceImplTest, ShouldRecord) {
   TestSyncService sync_service(true, ModelTypeSet(HISTORY_DELETE_DIRECTIVES));
-  UserEventService service(&sync_service, MakeBridge());
+  UserEventServiceImpl service(&sync_service, MakeBridge());
   service.RecordUserEvent(base::MakeUnique<UserEventSpecifics>());
   EXPECT_EQ(1u, processor().put_multimap().size());
 }
 
-TEST_F(UserEventServiceTest, SessionIdIsDifferent) {
+TEST_F(UserEventServiceImplTest, SessionIdIsDifferent) {
   TestSyncService sync_service(true, ModelTypeSet(HISTORY_DELETE_DIRECTIVES));
 
-  UserEventService service1(&sync_service, MakeBridge());
+  UserEventServiceImpl service1(&sync_service, MakeBridge());
   service1.RecordUserEvent(base::MakeUnique<UserEventSpecifics>());
   ASSERT_EQ(1u, processor().put_multimap().size());
   auto put1 = processor().put_multimap().begin();
   int64_t session_id1 = put1->second->specifics.user_event().session_id();
 
-  UserEventService service2(&sync_service, MakeBridge());
+  UserEventServiceImpl service2(&sync_service, MakeBridge());
   service2.RecordUserEvent(base::MakeUnique<UserEventSpecifics>());
   // The object processor() points to has changed to be |service2|'s processor.
   ASSERT_EQ(1u, processor().put_multimap().size());
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc
index b6f603b9..5587511 100644
--- a/content/browser/accessibility/browser_accessibility.cc
+++ b/content/browser/accessibility/browser_accessibility.cc
@@ -744,31 +744,6 @@
   return GetData().GetHtmlAttribute(html_attr, value);
 }
 
-bool BrowserAccessibility::GetAriaTristate(
-    const char* html_attr,
-    bool* is_defined,
-    bool* is_mixed) const {
-  *is_defined = false;
-  *is_mixed = false;
-
-  base::string16 value;
-  if (!GetHtmlAttribute(html_attr, &value) ||
-      value.empty() ||
-      base::EqualsASCII(value, "undefined")) {
-    return false;  // Not set (and *is_defined is also false)
-  }
-
-  *is_defined = true;
-
-  if (base::EqualsASCII(value, "true"))
-    return true;
-
-  if (base::EqualsASCII(value, "mixed"))
-    *is_mixed = true;
-
-  return false;  // Not set.
-}
-
 BrowserAccessibility* BrowserAccessibility::GetTable() const {
   BrowserAccessibility* table = const_cast<BrowserAccessibility*>(this);
   while (table && !table->IsTableLikeRole())
diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h
index 1d25cc4..e9df24c 100644
--- a/content/browser/accessibility/browser_accessibility.h
+++ b/content/browser/accessibility/browser_accessibility.h
@@ -285,24 +285,8 @@
 
   // Retrieve the value of a html attribute from the attribute map and
   // returns true if found.
-  bool GetHtmlAttribute(const char* attr, base::string16* value) const;
   bool GetHtmlAttribute(const char* attr, std::string* value) const;
-
-  // Utility method to handle special cases for ARIA booleans, tristates and
-  // booleans which have a "mixed" state.
-  //
-  // Warning: the term "Tristate" is used loosely by the spec and here,
-  // as some attributes support a 4th state.
-  //
-  // The following attributes are appropriate to use with this method:
-  // aria-selected  (selectable)
-  // aria-grabbed   (grabbable)
-  // aria-expanded  (expandable)
-  // aria-pressed   (toggleable/pressable) -- supports 4th "mixed" state
-  // aria-checked   (checkable) -- supports 4th "mixed state"
-  bool GetAriaTristate(const char* attr_name,
-                       bool* is_defined,
-                       bool* is_mixed) const;
+  bool GetHtmlAttribute(const char* attr, base::string16* value) const;
 
   base::string16 GetFontFamily() const;
   base::string16 GetLanguage() const;
diff --git a/content/browser/accessibility/browser_accessibility_android.cc b/content/browser/accessibility/browser_accessibility_android.cc
index ef7d0089..bea1cfc 100644
--- a/content/browser/accessibility/browser_accessibility_android.cc
+++ b/content/browser/accessibility/browser_accessibility_android.cc
@@ -140,28 +140,12 @@
 }
 
 bool BrowserAccessibilityAndroid::IsCheckable() const {
-  bool checkable = false;
-  bool is_aria_pressed_defined;
-  bool is_mixed;
-  GetAriaTristate("aria-pressed", &is_aria_pressed_defined, &is_mixed);
-  if (GetRole() == ui::AX_ROLE_CHECK_BOX ||
-      GetRole() == ui::AX_ROLE_RADIO_BUTTON ||
-      GetRole() == ui::AX_ROLE_MENU_ITEM_CHECK_BOX ||
-      GetRole() == ui::AX_ROLE_MENU_ITEM_RADIO ||
-      is_aria_pressed_defined) {
-    checkable = true;
-  }
-  // TODO(aleventhal) does this ever happen when checkable is not true yet?
-  if (HasIntAttribute(ui::AX_ATTR_CHECKED_STATE))
-    checkable = true;
-  return checkable;
+  return HasIntAttribute(ui::AX_ATTR_CHECKED_STATE);
 }
 
 bool BrowserAccessibilityAndroid::IsChecked() const {
-  const auto checked_state = static_cast<ui::AXCheckedState>(
-      GetIntAttribute(ui::AX_ATTR_CHECKED_STATE));
-  return (checked_state == ui::AX_CHECKED_STATE_TRUE ||
-          HasState(ui::AX_STATE_PRESSED));
+  return GetIntAttribute(ui::AX_ATTR_CHECKED_STATE) ==
+         ui::AX_CHECKED_STATE_TRUE;
 }
 
 bool BrowserAccessibilityAndroid::IsClickable() const {
@@ -197,8 +181,9 @@
 }
 
 bool BrowserAccessibilityAndroid::IsContentInvalid() const {
-  std::string invalid;
-  return GetHtmlAttribute("aria-invalid", &invalid);
+  return HasIntAttribute(ui::AX_ATTR_INVALID_STATE) &&
+         GetIntAttribute(ui::AX_ATTR_INVALID_STATE) !=
+             ui::AX_INVALID_STATE_FALSE;
 }
 
 bool BrowserAccessibilityAndroid::IsDismissable() const {
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm
index c0985dd..f0d696d 100644
--- a/content/browser/accessibility/browser_accessibility_cocoa.mm
+++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -1368,17 +1368,7 @@
           ui::AX_ATTR_CANVAS_HAS_FALLBACK)) {
     return NSAccessibilityGroupRole;
   }
-  if (role == ui::AX_ROLE_BUTTON || role == ui::AX_ROLE_TOGGLE_BUTTON) {
-    bool isAriaPressedDefined;
-    bool isMixed;
-    browserAccessibility_->GetAriaTristate("aria-pressed",
-                                           &isAriaPressedDefined,
-                                           &isMixed);
-    if (isAriaPressedDefined)
-      return NSAccessibilityCheckBoxRole;
-    else
-      return NSAccessibilityButtonRole;
-  }
+
   if ((browserAccessibility_->IsSimpleTextControl() &&
        browserAccessibility_->HasState(ui::AX_STATE_MULTILINE)) ||
       browserAccessibility_->IsRichTextControl()) {
@@ -1870,22 +1860,9 @@
   } else if ([role isEqualToString:NSAccessibilityButtonRole]) {
     // AXValue does not make sense for pure buttons.
     return @"";
-  } else if ([self internalRole] == ui::AX_ROLE_TOGGLE_BUTTON) {
-    int value = 0;
-    bool isAriaPressedDefined;
-    bool isMixed;
-    value = browserAccessibility_->GetAriaTristate(
-        "aria-pressed", &isAriaPressedDefined, &isMixed) ? 1 : 0;
-
-    if (isMixed)
-      value = 2;
-
-    return [NSNumber numberWithInt:value];
-
-  } else if ([role isEqualToString:NSAccessibilityCheckBoxRole] ||
-             [role isEqualToString:NSAccessibilityRadioButtonRole] ||
-             [self internalRole] == ui::AX_ROLE_MENU_ITEM_CHECK_BOX ||
-             [self internalRole] == ui::AX_ROLE_MENU_ITEM_RADIO) {
+  } else if (browserAccessibility_->HasIntAttribute(
+                 ui::AX_ATTR_CHECKED_STATE) ||
+             [role isEqualToString:NSAccessibilityRadioButtonRole]) {
     int value;
     const auto checkedState = static_cast<ui::AXCheckedState>(
         browserAccessibility_->GetIntAttribute(ui::AX_ATTR_CHECKED_STATE));
diff --git a/content/browser/accessibility/browser_accessibility_com_win.cc b/content/browser/accessibility/browser_accessibility_com_win.cc
index ecd86fa..46b1cd1 100644
--- a/content/browser/accessibility/browser_accessibility_com_win.cc
+++ b/content/browser/accessibility/browser_accessibility_com_win.cc
@@ -3692,13 +3692,8 @@
   IntAttributeToIA2(ui::AX_ATTR_SET_SIZE, "setsize");
   IntAttributeToIA2(ui::AX_ATTR_POS_IN_SET, "posinset");
 
-  if (ia_role() == ROLE_SYSTEM_CHECKBUTTON ||
-      ia_role() == ROLE_SYSTEM_RADIOBUTTON ||
-      ia2_role() == IA2_ROLE_CHECK_MENU_ITEM ||
-      ia2_role() == IA2_ROLE_RADIO_MENU_ITEM ||
-      ia2_role() == IA2_ROLE_TOGGLE_BUTTON) {
+  if (owner()->HasIntAttribute(ui::AX_ATTR_CHECKED_STATE))
     win_attributes_->ia2_attributes.push_back(L"checkable:true");
-  }
 
   // Expose live region attributes.
   StringAttributeToIA2(ui::AX_ATTR_LIVE_STATUS, "live");
@@ -5039,15 +5034,20 @@
 
   const auto checked_state = static_cast<ui::AXCheckedState>(
       owner()->GetIntAttribute(ui::AX_ATTR_CHECKED_STATE));
-  switch (checked_state) {
-    case ui::AX_CHECKED_STATE_TRUE:
-      ia_state |= STATE_SYSTEM_CHECKED;
-      break;
-    case ui::AX_CHECKED_STATE_MIXED:
-      ia_state |= STATE_SYSTEM_MIXED;
-      break;
-    default:
-      break;
+  if (checked_state) {
+    ia2_state |= IA2_STATE_CHECKABLE;
+    switch (checked_state) {
+      case ui::AX_CHECKED_STATE_TRUE:
+        ia_state |= owner()->GetRole() == ui::AX_ROLE_TOGGLE_BUTTON
+                        ? STATE_SYSTEM_PRESSED
+                        : STATE_SYSTEM_CHECKED;
+        break;
+      case ui::AX_CHECKED_STATE_MIXED:
+        ia_state |= STATE_SYSTEM_MIXED;
+        break;
+      default:
+        break;
+    }
   }
 
   if (owner()->HasState(ui::AX_STATE_COLLAPSED))
@@ -5073,8 +5073,6 @@
   // TODO(ctguil): Support STATE_SYSTEM_EXTSELECTABLE/accSelect.
   if (owner()->HasState(ui::AX_STATE_OFFSCREEN))
     ia_state |= STATE_SYSTEM_OFFSCREEN;
-  if (owner()->HasState(ui::AX_STATE_PRESSED))
-    ia_state |= STATE_SYSTEM_PRESSED;
   if (owner()->HasState(ui::AX_STATE_PROTECTED))
     ia_state |= STATE_SYSTEM_PROTECTED;
   if (owner()->HasState(ui::AX_STATE_REQUIRED))
@@ -5166,7 +5164,6 @@
       break;
     case ui::AX_ROLE_CHECK_BOX:
       ia_role = ROLE_SYSTEM_CHECKBUTTON;
-      ia2_state |= IA2_STATE_CHECKABLE;
       break;
     case ui::AX_ROLE_COLOR_WELL:
       ia_role = ROLE_SYSTEM_TEXT;
@@ -5355,7 +5352,6 @@
     case ui::AX_ROLE_MENU_ITEM_CHECK_BOX:
       ia_role = ROLE_SYSTEM_MENUITEM;
       ia2_role = IA2_ROLE_CHECK_MENU_ITEM;
-      ia2_state |= IA2_STATE_CHECKABLE;
       break;
     case ui::AX_ROLE_MENU_ITEM_RADIO:
       ia_role = ROLE_SYSTEM_MENUITEM;
@@ -5406,7 +5402,6 @@
       break;
     case ui::AX_ROLE_RADIO_BUTTON:
       ia_role = ROLE_SYSTEM_RADIOBUTTON;
-      ia2_state = IA2_STATE_CHECKABLE;
       break;
     case ui::AX_ROLE_RADIO_GROUP:
       ia_role = ROLE_SYSTEM_GROUPING;
@@ -5569,7 +5564,8 @@
   // We always set the READONLY state for elements that have the
   // aria-readonly attribute and for a few roles (in the switch above),
   // including read-only text fields.
-  // The majority of focusable controls should not have the read-only state set.
+  // The majority of focusable controls should not have the read-only state
+  // set.
   if (owner()->HasState(ui::AX_STATE_FOCUSABLE) &&
       ia_role != ROLE_SYSTEM_DOCUMENT && ia_role != ROLE_SYSTEM_TEXT) {
     ia_state &= ~(STATE_SYSTEM_READONLY);
diff --git a/content/browser/accessibility/browser_accessibility_manager_mac.h b/content/browser/accessibility/browser_accessibility_manager_mac.h
index 406793a..5f5f83c 100644
--- a/content/browser/accessibility/browser_accessibility_manager_mac.h
+++ b/content/browser/accessibility/browser_accessibility_manager_mac.h
@@ -49,10 +49,6 @@
   void OnNodeDataWillChange(ui::AXTree* tree,
                             const ui::AXNodeData& old_node_data,
                             const ui::AXNodeData& new_node_data) override;
-  void OnStateChanged(ui::AXTree* tree,
-                      ui::AXNode* node,
-                      ui::AXState state,
-                      bool new_value) override;
 
   // Returns an autoreleased object.
   NSDictionary* GetUserInfoForSelectedTextChangedNotification();
diff --git a/content/browser/accessibility/browser_accessibility_manager_mac.mm b/content/browser/accessibility/browser_accessibility_manager_mac.mm
index 51f453f6..11ffb68e 100644
--- a/content/browser/accessibility/browser_accessibility_manager_mac.mm
+++ b/content/browser/accessibility/browser_accessibility_manager_mac.mm
@@ -411,18 +411,6 @@
   }
 }
 
-void BrowserAccessibilityManagerMac::OnStateChanged(ui::AXTree* tree,
-                                                    ui::AXNode* ax_node,
-                                                    ui::AXState state,
-                                                    bool new_value) {
-  if (state != ui::AX_STATE_PRESSED)
-    return;
-
-  BrowserAccessibility* node = GetFromID(ax_node->id());
-  NotifyAccessibilityEvent(BrowserAccessibilityEvent::FromTreeChange,
-                           ui::AX_EVENT_CHECKED_STATE_CHANGED, node);
-}
-
 NSDictionary* BrowserAccessibilityManagerMac::
     GetUserInfoForSelectedTextChangedNotification() {
   NSMutableDictionary* user_info = [[[NSMutableDictionary alloc] init]
diff --git a/content/browser/compositor/gpu_process_transport_factory.cc b/content/browser/compositor/gpu_process_transport_factory.cc
index 1c2caa7..2577ba21 100644
--- a/content/browser/compositor/gpu_process_transport_factory.cc
+++ b/content/browser/compositor/gpu_process_transport_factory.cc
@@ -793,9 +793,9 @@
     data->display->SetOutputIsSecure(secure);
 }
 
-const cc::RendererSettings& GpuProcessTransportFactory::GetRendererSettings()
+const cc::ResourceSettings& GpuProcessTransportFactory::GetResourceSettings()
     const {
-  return renderer_settings_;
+  return renderer_settings_.resource_settings;
 }
 
 void GpuProcessTransportFactory::AddObserver(
diff --git a/content/browser/compositor/gpu_process_transport_factory.h b/content/browser/compositor/gpu_process_transport_factory.h
index ed3db87..9ce2a46 100644
--- a/content/browser/compositor/gpu_process_transport_factory.h
+++ b/content/browser/compositor/gpu_process_transport_factory.h
@@ -23,6 +23,7 @@
 #include "ui/compositor/compositor.h"
 
 namespace cc {
+class ResourceSettings;
 class SingleThreadTaskGraphRunner;
 class SoftwareOutputDevice;
 class SurfaceManager;
@@ -52,7 +53,7 @@
   double GetRefreshRate() const override;
   gpu::GpuMemoryBufferManager* GetGpuMemoryBufferManager() override;
   cc::TaskGraphRunner* GetTaskGraphRunner() override;
-  const cc::RendererSettings& GetRendererSettings() const override;
+  const cc::ResourceSettings& GetResourceSettings() const override;
   void AddObserver(ui::ContextFactoryObserver* observer) override;
   void RemoveObserver(ui::ContextFactoryObserver* observer) override;
 
diff --git a/content/child/BUILD.gn b/content/child/BUILD.gn
index 37f961b1..771e200 100644
--- a/content/child/BUILD.gn
+++ b/content/child/BUILD.gn
@@ -175,6 +175,8 @@
     "sync_load_response.h",
     "thread_safe_sender.cc",
     "thread_safe_sender.h",
+    "throttling_url_loader.cc",
+    "throttling_url_loader.h",
     "url_loader_client_impl.cc",
     "url_loader_client_impl.h",
     "url_response_body_consumer.cc",
diff --git a/content/child/fileapi/webfilesystem_impl.cc b/content/child/fileapi/webfilesystem_impl.cc
index 62204885..8c55be9 100644
--- a/content/child/fileapi/webfilesystem_impl.cc
+++ b/content/child/fileapi/webfilesystem_impl.cc
@@ -397,6 +397,7 @@
 }
 
 WebFileSystemImpl::~WebFileSystemImpl() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   g_webfilesystem_tls.Pointer()->Set(NULL);
 }
 
@@ -654,21 +655,21 @@
 
 int WebFileSystemImpl::RegisterCallbacks(
     const WebFileSystemCallbacks& callbacks) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   int id = next_callbacks_id_++;
   callbacks_[id] = callbacks;
   return id;
 }
 
 WebFileSystemCallbacks WebFileSystemImpl::GetCallbacks(int callbacks_id) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   CallbacksMap::iterator found = callbacks_.find(callbacks_id);
   DCHECK(found != callbacks_.end());
   return found->second;
 }
 
 void WebFileSystemImpl::UnregisterCallbacks(int callbacks_id) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   CallbacksMap::iterator found = callbacks_.find(callbacks_id);
   DCHECK(found != callbacks_.end());
   callbacks_.erase(found);
diff --git a/content/child/fileapi/webfilesystem_impl.h b/content/child/fileapi/webfilesystem_impl.h
index bef376f..4efe2f9 100644
--- a/content/child/fileapi/webfilesystem_impl.h
+++ b/content/child/fileapi/webfilesystem_impl.h
@@ -10,7 +10,7 @@
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "base/threading/non_thread_safe.h"
+#include "base/sequence_checker.h"
 #include "content/public/child/worker_thread.h"
 #include "third_party/WebKit/public/platform/WebFileSystem.h"
 
@@ -26,8 +26,7 @@
 namespace content {
 
 class WebFileSystemImpl : public blink::WebFileSystem,
-                          public WorkerThread::Observer,
-                          public base::NonThreadSafe {
+                          public WorkerThread::Observer {
  public:
   class WaitableCallbackResults;
 
@@ -107,6 +106,8 @@
   int next_callbacks_id_;
   WaitableCallbackResultsMap waitable_results_;
 
+  SEQUENCE_CHECKER(sequence_checker_);
+
   DISALLOW_COPY_AND_ASSIGN(WebFileSystemImpl);
 };
 
diff --git a/content/child/request_extra_data.h b/content/child/request_extra_data.h
index 214ba6ff..79fafdc 100644
--- a/content/child/request_extra_data.h
+++ b/content/child/request_extra_data.h
@@ -13,6 +13,7 @@
 #include "content/common/content_export.h"
 #include "content/common/navigation_params.h"
 #include "content/common/url_loader_factory.mojom.h"
+#include "content/public/child/url_loader_throttle.h"
 #include "third_party/WebKit/public/platform/WebPageVisibilityState.h"
 #include "third_party/WebKit/public/platform/WebString.h"
 #include "third_party/WebKit/public/platform/WebURLRequest.h"
@@ -175,6 +176,14 @@
     url_loader_factory_override_ = factory;
   }
 
+  std::vector<std::unique_ptr<URLLoaderThrottle>> TakeURLLoaderThrottles() {
+    return std::move(url_loader_throttles_);
+  }
+  void set_url_loader_throttles(
+      std::vector<std::unique_ptr<URLLoaderThrottle>> throttles) {
+    url_loader_throttles_ = std::move(throttles);
+  }
+
   void CopyToResourceRequest(ResourceRequest* request) const;
 
  private:
@@ -200,6 +209,7 @@
   bool block_mixed_plugin_content_;
   bool navigation_initiated_by_renderer_;
   mojom::URLLoaderFactory* url_loader_factory_override_;
+  std::vector<std::unique_ptr<URLLoaderThrottle>> url_loader_throttles_;
 
   DISALLOW_COPY_AND_ASSIGN(RequestExtraData);
 };
diff --git a/content/child/resource_dispatcher.cc b/content/child/resource_dispatcher.cc
index bf1ab753..218efb1 100644
--- a/content/child/resource_dispatcher.cc
+++ b/content/child/resource_dispatcher.cc
@@ -27,6 +27,7 @@
 #include "content/child/shared_memory_received_data_factory.h"
 #include "content/child/site_isolation_stats_gatherer.h"
 #include "content/child/sync_load_response.h"
+#include "content/child/throttling_url_loader.h"
 #include "content/child/url_loader_client_impl.h"
 #include "content/common/inter_process_time_ticks_converter.h"
 #include "content/common/navigation_params.h"
@@ -579,12 +580,18 @@
     int routing_id,
     SyncLoadResponse* response,
     blink::WebURLRequest::LoadingIPCType ipc_type,
-    mojom::URLLoaderFactory* url_loader_factory) {
+    mojom::URLLoaderFactory* url_loader_factory,
+    std::vector<std::unique_ptr<URLLoaderThrottle>> throttles) {
   CheckSchemeForReferrerPolicy(*request);
 
   SyncLoadResult result;
 
   if (ipc_type == blink::WebURLRequest::LoadingIPCType::kMojo) {
+    // TODO(yzshen): There is no way to apply a throttle to sync loading. We
+    // could use async loading + sync handle watching to emulate this behavior.
+    // That may require to extend the bindings API to change the priority of
+    // messages. It would result in more messages during this blocking
+    // operation, but sync loading is discouraged anyway.
     if (!url_loader_factory->SyncLoad(
             routing_id, MakeRequestID(), *request, &result)) {
       response->error_code = net::ERR_FAILED;
@@ -625,6 +632,7 @@
     std::unique_ptr<RequestPeer> peer,
     blink::WebURLRequest::LoadingIPCType ipc_type,
     mojom::URLLoaderFactory* url_loader_factory,
+    std::vector<std::unique_ptr<URLLoaderThrottle>> throttles,
     mojo::ScopedDataPipeConsumerHandle consumer_handle) {
   CheckSchemeForReferrerPolicy(*request);
 
@@ -659,12 +667,10 @@
         loading_task_runner ? loading_task_runner : thread_task_runner_;
     std::unique_ptr<URLLoaderClientImpl> client(
         new URLLoaderClientImpl(request_id, this, std::move(task_runner)));
-    mojom::URLLoaderPtr url_loader;
-    mojom::URLLoaderClientPtr client_ptr;
-    client->Bind(&client_ptr);
-    url_loader_factory->CreateLoaderAndStart(
-        MakeRequest(&url_loader), routing_id, request_id,
-        mojom::kURLLoadOptionNone, *request, std::move(client_ptr));
+    std::unique_ptr<ThrottlingURLLoader> url_loader =
+        ThrottlingURLLoader::CreateLoaderAndStart(
+            url_loader_factory, std::move(throttles), routing_id, request_id,
+            mojom::kURLLoadOptionNone, std::move(request), client.get());
     pending_requests_[request_id]->url_loader = std::move(url_loader);
     pending_requests_[request_id]->url_loader_client = std::move(client);
   } else {
diff --git a/content/child/resource_dispatcher.h b/content/child/resource_dispatcher.h
index 9830c7d..82708ba6 100644
--- a/content/child/resource_dispatcher.h
+++ b/content/child/resource_dispatcher.h
@@ -23,6 +23,7 @@
 #include "base/time/time.h"
 #include "content/common/content_export.h"
 #include "content/common/url_loader.mojom.h"
+#include "content/public/child/url_loader_throttle.h"
 #include "content/public/common/resource_type.h"
 #include "ipc/ipc_listener.h"
 #include "ipc/ipc_sender.h"
@@ -47,6 +48,7 @@
 class SharedMemoryReceivedDataFactory;
 struct SiteIsolationResponseMetaData;
 struct SyncLoadResponse;
+class ThrottlingURLLoader;
 class URLLoaderClientImpl;
 
 namespace mojom {
@@ -76,11 +78,13 @@
   //
   // |routing_id| is used to associated the bridge with a frame's network
   // context.
-  virtual void StartSync(std::unique_ptr<ResourceRequest> request,
-                         int routing_id,
-                         SyncLoadResponse* response,
-                         blink::WebURLRequest::LoadingIPCType ipc_type,
-                         mojom::URLLoaderFactory* url_loader_factory);
+  virtual void StartSync(
+      std::unique_ptr<ResourceRequest> request,
+      int routing_id,
+      SyncLoadResponse* response,
+      blink::WebURLRequest::LoadingIPCType ipc_type,
+      mojom::URLLoaderFactory* url_loader_factory,
+      std::vector<std::unique_ptr<URLLoaderThrottle>> throttles);
 
   // Call this method to initiate the request. If this method succeeds, then
   // the peer's methods will be called asynchronously to report various events.
@@ -100,6 +104,7 @@
       std::unique_ptr<RequestPeer> peer,
       blink::WebURLRequest::LoadingIPCType ipc_type,
       mojom::URLLoaderFactory* url_loader_factory,
+      std::vector<std::unique_ptr<URLLoaderThrottle>> throttles,
       mojo::ScopedDataPipeConsumerHandle consumer_handle);
 
   // Removes a request from the |pending_requests_| list, returning true if the
@@ -190,7 +195,7 @@
     int buffer_size;
 
     // For mojo loading.
-    mojom::URLLoaderPtr url_loader;
+    std::unique_ptr<ThrottlingURLLoader> url_loader;
     std::unique_ptr<URLLoaderClientImpl> url_loader_client;
   };
   using PendingRequestMap = std::map<int, std::unique_ptr<PendingRequestInfo>>;
diff --git a/content/child/resource_dispatcher_unittest.cc b/content/child/resource_dispatcher_unittest.cc
index 09b4de9..1b3e0a7 100644
--- a/content/child/resource_dispatcher_unittest.cc
+++ b/content/child/resource_dispatcher_unittest.cc
@@ -230,6 +230,7 @@
     int request_id = dispatcher()->StartAsync(
         std::move(request), 0, nullptr, url::Origin(), std::move(peer),
         blink::WebURLRequest::LoadingIPCType::kChromeIPC, nullptr,
+        std::vector<std::unique_ptr<URLLoaderThrottle>>(),
         mojo::ScopedDataPipeConsumerHandle());
     peer_context->request_id = request_id;
     return request_id;
diff --git a/content/child/throttling_url_loader.cc b/content/child/throttling_url_loader.cc
new file mode 100644
index 0000000..fc77bc1
--- /dev/null
+++ b/content/child/throttling_url_loader.cc
@@ -0,0 +1,243 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/child/throttling_url_loader.h"
+
+namespace content {
+
+// static
+std::unique_ptr<ThrottlingURLLoader> ThrottlingURLLoader::CreateLoaderAndStart(
+    mojom::URLLoaderFactory* factory,
+    std::vector<std::unique_ptr<URLLoaderThrottle>> throttles,
+    int32_t routing_id,
+    int32_t request_id,
+    uint32_t options,
+    std::unique_ptr<ResourceRequest> url_request,
+    mojom::URLLoaderClient* client) {
+  std::unique_ptr<ThrottlingURLLoader> loader(
+      new ThrottlingURLLoader(std::move(throttles), client));
+  loader->Start(factory, routing_id, request_id, options,
+                std::move(url_request));
+  return loader;
+}
+
+ThrottlingURLLoader::~ThrottlingURLLoader() {}
+
+void ThrottlingURLLoader::FollowRedirect() {
+  if (url_loader_)
+    url_loader_->FollowRedirect();
+}
+
+void ThrottlingURLLoader::SetPriority(net::RequestPriority priority,
+                                      int32_t intra_priority_value) {
+  if (!url_loader_ && !cancelled_by_throttle_) {
+    DCHECK_EQ(DEFERRED_START, deferred_stage_);
+    set_priority_cached_ = true;
+    priority_ = priority;
+    intra_priority_value_ = intra_priority_value;
+    return;
+  }
+
+  url_loader_->SetPriority(priority, intra_priority_value);
+}
+
+ThrottlingURLLoader::ThrottlingURLLoader(
+    std::vector<std::unique_ptr<URLLoaderThrottle>> throttles,
+    mojom::URLLoaderClient* client)
+    : forwarding_client_(client), client_binding_(this) {
+  if (throttles.size() > 0) {
+    // TODO(yzshen): Implement a URLLoaderThrottle subclass which handles a list
+    // of URLLoaderThrottles.
+    CHECK_EQ(1u, throttles.size());
+    throttle_ = std::move(throttles[0]);
+    throttle_->set_delegate(this);
+  }
+}
+
+void ThrottlingURLLoader::Start(mojom::URLLoaderFactory* factory,
+                                int32_t routing_id,
+                                int32_t request_id,
+                                uint32_t options,
+                                std::unique_ptr<ResourceRequest> url_request) {
+  DCHECK_EQ(DEFERRED_NONE, deferred_stage_);
+  DCHECK(!cancelled_by_throttle_);
+
+  if (throttle_) {
+    bool deferred = false;
+    throttle_->WillStartRequest(url_request->url, url_request->load_flags,
+                                url_request->resource_type, &deferred);
+    if (cancelled_by_throttle_)
+      return;
+
+    if (deferred) {
+      deferred_stage_ = DEFERRED_START;
+      url_loader_factory_ = factory;
+      routing_id_ = routing_id;
+      request_id_ = request_id;
+      options_ = options;
+      url_request_ = std::move(url_request);
+      return;
+    }
+  }
+
+  factory->CreateLoaderAndStart(mojo::MakeRequest(&url_loader_), routing_id,
+                                request_id, options, *url_request,
+                                client_binding_.CreateInterfacePtrAndBind());
+}
+
+void ThrottlingURLLoader::OnReceiveResponse(
+    const ResourceResponseHead& response_head,
+    const base::Optional<net::SSLInfo>& ssl_info,
+    mojom::DownloadedTempFilePtr downloaded_file) {
+  DCHECK_EQ(DEFERRED_NONE, deferred_stage_);
+  DCHECK(!cancelled_by_throttle_);
+
+  if (throttle_) {
+    bool deferred = false;
+    throttle_->WillProcessResponse(&deferred);
+    if (cancelled_by_throttle_)
+      return;
+
+    if (deferred) {
+      deferred_stage_ = DEFERRED_RESPONSE;
+      response_head_ = response_head;
+      ssl_info_ = ssl_info;
+      downloaded_file_ = std::move(downloaded_file);
+      client_binding_.PauseIncomingMethodCallProcessing();
+      return;
+    }
+  }
+
+  forwarding_client_->OnReceiveResponse(response_head, ssl_info,
+                                        std::move(downloaded_file));
+}
+
+void ThrottlingURLLoader::OnReceiveRedirect(
+    const net::RedirectInfo& redirect_info,
+    const ResourceResponseHead& response_head) {
+  DCHECK_EQ(DEFERRED_NONE, deferred_stage_);
+  DCHECK(!cancelled_by_throttle_);
+
+  if (throttle_) {
+    bool deferred = false;
+    throttle_->WillRedirectRequest(redirect_info, &deferred);
+    if (cancelled_by_throttle_)
+      return;
+
+    if (deferred) {
+      deferred_stage_ = DEFERRED_REDIRECT;
+      redirect_info_ = redirect_info;
+      response_head_ = response_head;
+      client_binding_.PauseIncomingMethodCallProcessing();
+      return;
+    }
+  }
+
+  forwarding_client_->OnReceiveRedirect(redirect_info, response_head);
+}
+
+void ThrottlingURLLoader::OnDataDownloaded(int64_t data_len,
+                                           int64_t encoded_data_len) {
+  DCHECK_EQ(DEFERRED_NONE, deferred_stage_);
+  DCHECK(!cancelled_by_throttle_);
+
+  forwarding_client_->OnDataDownloaded(data_len, encoded_data_len);
+}
+
+void ThrottlingURLLoader::OnUploadProgress(
+    int64_t current_position,
+    int64_t total_size,
+    OnUploadProgressCallback ack_callback) {
+  DCHECK_EQ(DEFERRED_NONE, deferred_stage_);
+  DCHECK(!cancelled_by_throttle_);
+
+  forwarding_client_->OnUploadProgress(current_position, total_size,
+                                       std::move(ack_callback));
+}
+
+void ThrottlingURLLoader::OnReceiveCachedMetadata(
+    const std::vector<uint8_t>& data) {
+  DCHECK_EQ(DEFERRED_NONE, deferred_stage_);
+  DCHECK(!cancelled_by_throttle_);
+
+  forwarding_client_->OnReceiveCachedMetadata(data);
+}
+
+void ThrottlingURLLoader::OnTransferSizeUpdated(int32_t transfer_size_diff) {
+  DCHECK_EQ(DEFERRED_NONE, deferred_stage_);
+  DCHECK(!cancelled_by_throttle_);
+
+  forwarding_client_->OnTransferSizeUpdated(transfer_size_diff);
+}
+
+void ThrottlingURLLoader::OnStartLoadingResponseBody(
+    mojo::ScopedDataPipeConsumerHandle body) {
+  DCHECK_EQ(DEFERRED_NONE, deferred_stage_);
+  DCHECK(!cancelled_by_throttle_);
+
+  forwarding_client_->OnStartLoadingResponseBody(std::move(body));
+}
+
+void ThrottlingURLLoader::OnComplete(
+    const ResourceRequestCompletionStatus& status) {
+  DCHECK_EQ(DEFERRED_NONE, deferred_stage_);
+  DCHECK(!cancelled_by_throttle_);
+
+  forwarding_client_->OnComplete(status);
+}
+
+void ThrottlingURLLoader::CancelWithError(int error_code) {
+  // TODO(yzshen): Support a mode that cancellation also deletes the disk cache
+  // entry.
+  if (cancelled_by_throttle_)
+    return;
+
+  cancelled_by_throttle_ = true;
+
+  ResourceRequestCompletionStatus request_complete_data;
+  request_complete_data.error_code = error_code;
+  request_complete_data.completion_time = base::TimeTicks::Now();
+
+  deferred_stage_ = DEFERRED_NONE;
+  client_binding_.Close();
+  url_loader_.reset();
+
+  forwarding_client_->OnComplete(request_complete_data);
+}
+
+void ThrottlingURLLoader::Resume() {
+  if (cancelled_by_throttle_ || deferred_stage_ == DEFERRED_NONE)
+    return;
+
+  switch (deferred_stage_) {
+    case DEFERRED_START: {
+      url_loader_factory_->CreateLoaderAndStart(
+          mojo::MakeRequest(&url_loader_), routing_id_, request_id_, options_,
+          *url_request_, client_binding_.CreateInterfacePtrAndBind());
+
+      if (set_priority_cached_) {
+        set_priority_cached_ = false;
+        url_loader_->SetPriority(priority_, intra_priority_value_);
+      }
+      break;
+    }
+    case DEFERRED_REDIRECT: {
+      client_binding_.ResumeIncomingMethodCallProcessing();
+      forwarding_client_->OnReceiveRedirect(redirect_info_, response_head_);
+      break;
+    }
+    case DEFERRED_RESPONSE: {
+      client_binding_.ResumeIncomingMethodCallProcessing();
+      forwarding_client_->OnReceiveResponse(response_head_, ssl_info_,
+                                            std::move(downloaded_file_));
+      break;
+    }
+    default:
+      NOTREACHED();
+      break;
+  }
+  deferred_stage_ = DEFERRED_NONE;
+}
+
+}  // namespace content
diff --git a/content/child/throttling_url_loader.h b/content/child/throttling_url_loader.h
new file mode 100644
index 0000000..5f3b088
--- /dev/null
+++ b/content/child/throttling_url_loader.h
@@ -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.
+
+#ifndef CONTENT_CHILD_THROTTLING_URL_LOADER_H_
+#define CONTENT_CHILD_THROTTLING_URL_LOADER_H_
+
+#include <memory>
+
+#include "content/common/content_export.h"
+#include "content/common/url_loader.mojom.h"
+#include "content/common/url_loader_factory.mojom.h"
+#include "content/public/child/url_loader_throttle.h"
+#include "mojo/public/cpp/bindings/binding.h"
+
+namespace content {
+
+namespace mojom {
+class URLLoaderFactory;
+}
+
+// ThrottlingURLLoader is a wrapper around the mojom::URLLoader[Factory]
+// interfaces. It applies a list of URLLoaderThrottle instances which could
+// defer, resume or cancel the URL loading.
+class CONTENT_EXPORT ThrottlingURLLoader : public mojom::URLLoaderClient,
+                                           public URLLoaderThrottle::Delegate {
+ public:
+  // |factory| and |client| must stay alive during the lifetime of the returned
+  // object.
+  static std::unique_ptr<ThrottlingURLLoader> CreateLoaderAndStart(
+      mojom::URLLoaderFactory* factory,
+      std::vector<std::unique_ptr<URLLoaderThrottle>> throttles,
+      int32_t routing_id,
+      int32_t request_id,
+      uint32_t options,
+      std::unique_ptr<ResourceRequest> url_request,
+      mojom::URLLoaderClient* client);
+
+  ~ThrottlingURLLoader() override;
+
+  void FollowRedirect();
+  void SetPriority(net::RequestPriority priority, int32_t intra_priority_value);
+
+ private:
+  ThrottlingURLLoader(std::vector<std::unique_ptr<URLLoaderThrottle>> throttles,
+                      mojom::URLLoaderClient* client);
+
+  void Start(mojom::URLLoaderFactory* factory,
+             int32_t routing_id,
+             int32_t request_id,
+             uint32_t options,
+             std::unique_ptr<ResourceRequest> url_request);
+
+  // mojom::URLLoaderClient implementation:
+  void OnReceiveResponse(const ResourceResponseHead& response_head,
+                         const base::Optional<net::SSLInfo>& ssl_info,
+                         mojom::DownloadedTempFilePtr downloaded_file) override;
+  void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
+                         const ResourceResponseHead& response_head) override;
+  void OnDataDownloaded(int64_t data_len, int64_t encoded_data_len) override;
+  void OnUploadProgress(int64_t current_position,
+                        int64_t total_size,
+                        OnUploadProgressCallback ack_callback) override;
+  void OnReceiveCachedMetadata(const std::vector<uint8_t>& data) override;
+  void OnTransferSizeUpdated(int32_t transfer_size_diff) override;
+  void OnStartLoadingResponseBody(
+      mojo::ScopedDataPipeConsumerHandle body) override;
+  void OnComplete(const ResourceRequestCompletionStatus& status) override;
+
+  // URLLoaderThrottle::Delegate:
+  void CancelWithError(int error_code) override;
+  void Resume() override;
+
+  enum DeferredStage {
+    DEFERRED_NONE,
+    DEFERRED_START,
+    DEFERRED_REDIRECT,
+    DEFERRED_RESPONSE
+  };
+  DeferredStage deferred_stage_ = DEFERRED_NONE;
+  bool cancelled_by_throttle_ = false;
+
+  std::unique_ptr<URLLoaderThrottle> throttle_;
+
+  mojom::URLLoaderClient* forwarding_client_;
+  mojo::Binding<mojom::URLLoaderClient> client_binding_;
+
+  mojom::URLLoaderPtr url_loader_;
+
+  // Set if start is deferred.
+  mojom::URLLoaderFactory* url_loader_factory_ = nullptr;
+  int32_t routing_id_ = -1;
+  int32_t request_id_ = -1;
+  uint32_t options_ = mojom::kURLLoadOptionNone;
+  std::unique_ptr<ResourceRequest> url_request_;
+
+  // Set if either response or redirect is deferred.
+  ResourceResponseHead response_head_;
+
+  // Set if response is deferred.
+  base::Optional<net::SSLInfo> ssl_info_;
+  mojom::DownloadedTempFilePtr downloaded_file_;
+
+  // Set if redirect is deferred.
+  net::RedirectInfo redirect_info_;
+
+  // Set if request is deferred and SetPriority() is called.
+  bool set_priority_cached_ = false;
+  net::RequestPriority priority_ = net::MINIMUM_PRIORITY;
+  int32_t intra_priority_value_ = 0;
+
+  DISALLOW_COPY_AND_ASSIGN(ThrottlingURLLoader);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_CHILD_THROTTLING_URL_LOADER_H_
diff --git a/content/child/throttling_url_loader_unittest.cc b/content/child/throttling_url_loader_unittest.cc
new file mode 100644
index 0000000..89d9c09
--- /dev/null
+++ b/content/child/throttling_url_loader_unittest.cc
@@ -0,0 +1,560 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/child/throttling_url_loader.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "content/common/url_loader.mojom.h"
+#include "content/common/url_loader_factory.mojom.h"
+#include "content/public/child/url_loader_throttle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+namespace {
+
+class TestURLLoaderFactory : public mojom::URLLoaderFactory {
+ public:
+  TestURLLoaderFactory() : binding_(this) {
+    binding_.Bind(mojo::MakeRequest(&factory_ptr_));
+  }
+
+  mojom::URLLoaderFactoryPtr& factory_ptr() { return factory_ptr_; }
+  mojom::URLLoaderClientPtr& client_ptr() { return client_ptr_; }
+
+  size_t create_loader_and_start_called() const {
+    return create_loader_and_start_called_;
+  }
+
+  void NotifyClientOnReceiveResponse() {
+    client_ptr_->OnReceiveResponse(ResourceResponseHead(), base::nullopt,
+                                   nullptr);
+  }
+
+  void NotifyClientOnReceiveRedirect() {
+    client_ptr_->OnReceiveRedirect(net::RedirectInfo(), ResourceResponseHead());
+  }
+
+  void NotifyClientOnComplete(int error_code) {
+    ResourceRequestCompletionStatus data;
+    data.error_code = error_code;
+    client_ptr_->OnComplete(data);
+  }
+
+ private:
+  // mojom::URLLoaderFactory implementation.
+  void CreateLoaderAndStart(mojom::URLLoaderRequest request,
+                            int32_t routing_id,
+                            int32_t request_id,
+                            uint32_t options,
+                            const ResourceRequest& url_request,
+                            mojom::URLLoaderClientPtr client) override {
+    create_loader_and_start_called_++;
+
+    client_ptr_ = std::move(client);
+  }
+
+  void SyncLoad(int32_t routing_id,
+                int32_t request_id,
+                const ResourceRequest& request,
+                SyncLoadCallback callback) override {
+    NOTREACHED();
+  }
+
+  size_t create_loader_and_start_called_ = 0;
+
+  mojo::Binding<mojom::URLLoaderFactory> binding_;
+  mojom::URLLoaderFactoryPtr factory_ptr_;
+  mojom::URLLoaderClientPtr client_ptr_;
+  DISALLOW_COPY_AND_ASSIGN(TestURLLoaderFactory);
+};
+
+class TestURLLoaderClient : public mojom::URLLoaderClient {
+ public:
+  TestURLLoaderClient() {}
+
+  size_t on_received_response_called() const {
+    return on_received_response_called_;
+  }
+
+  size_t on_received_redirect_called() const {
+    return on_received_redirect_called_;
+  }
+
+  size_t on_complete_called() const { return on_complete_called_; }
+
+  using OnCompleteCallback = base::Callback<void(int error_code)>;
+  void set_on_complete_callback(const OnCompleteCallback& callback) {
+    on_complete_callback_ = callback;
+  }
+
+ private:
+  // mojom::URLLoaderClient implementation:
+  void OnReceiveResponse(
+      const ResourceResponseHead& response_head,
+      const base::Optional<net::SSLInfo>& ssl_info,
+      mojom::DownloadedTempFilePtr downloaded_file) override {
+    on_received_response_called_++;
+  }
+  void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
+                         const ResourceResponseHead& response_head) override {
+    on_received_redirect_called_++;
+  }
+  void OnDataDownloaded(int64_t data_len, int64_t encoded_data_len) override {}
+  void OnUploadProgress(int64_t current_position,
+                        int64_t total_size,
+                        OnUploadProgressCallback ack_callback) override {}
+  void OnReceiveCachedMetadata(const std::vector<uint8_t>& data) override {}
+  void OnTransferSizeUpdated(int32_t transfer_size_diff) override {}
+  void OnStartLoadingResponseBody(
+      mojo::ScopedDataPipeConsumerHandle body) override {}
+  void OnComplete(const ResourceRequestCompletionStatus& status) override {
+    on_complete_called_++;
+    if (on_complete_callback_)
+      on_complete_callback_.Run(status.error_code);
+  }
+
+  size_t on_received_response_called_ = 0;
+  size_t on_received_redirect_called_ = 0;
+  size_t on_complete_called_ = 0;
+
+  OnCompleteCallback on_complete_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestURLLoaderClient);
+};
+
+class TestURLLoaderThrottle : public URLLoaderThrottle {
+ public:
+  TestURLLoaderThrottle() {}
+
+  using ThrottleCallback =
+      base::Callback<void(URLLoaderThrottle::Delegate* delegate, bool* defer)>;
+
+  size_t will_start_request_called() const {
+    return will_start_request_called_;
+  }
+  size_t will_redirect_request_called() const {
+    return will_redirect_request_called_;
+  }
+  size_t will_process_response_called() const {
+    return will_process_response_called_;
+  }
+
+  void set_will_start_request_callback(const ThrottleCallback& callback) {
+    will_start_request_callback_ = callback;
+  }
+
+  void set_will_redirect_request_callback(const ThrottleCallback& callback) {
+    will_redirect_request_callback_ = callback;
+  }
+
+  void set_will_process_response_callback(const ThrottleCallback& callback) {
+    will_process_response_callback_ = callback;
+  }
+
+  Delegate* delegate() const { return delegate_; }
+
+ private:
+  // URLLoaderThrottle implementation.
+  void WillStartRequest(const GURL& url,
+                        int load_flags,
+                        ResourceType resource_type,
+                        bool* defer) override {
+    will_start_request_called_++;
+    if (will_start_request_callback_)
+      will_start_request_callback_.Run(delegate_, defer);
+  }
+
+  void WillRedirectRequest(const net::RedirectInfo& redirect_info,
+                           bool* defer) override {
+    will_redirect_request_called_++;
+    if (will_redirect_request_callback_)
+      will_redirect_request_callback_.Run(delegate_, defer);
+  }
+
+  void WillProcessResponse(bool* defer) override {
+    will_process_response_called_++;
+    if (will_process_response_callback_)
+      will_process_response_callback_.Run(delegate_, defer);
+  }
+
+  size_t will_start_request_called_ = 0;
+  size_t will_redirect_request_called_ = 0;
+  size_t will_process_response_called_ = 0;
+
+  ThrottleCallback will_start_request_callback_;
+  ThrottleCallback will_redirect_request_callback_;
+  ThrottleCallback will_process_response_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestURLLoaderThrottle);
+};
+
+class ThrottlingURLLoaderTest : public testing::Test {
+ public:
+  ThrottlingURLLoaderTest() {}
+
+ protected:
+  // testing::Test implementation.
+  void SetUp() override {
+    auto throttle = base::MakeUnique<TestURLLoaderThrottle>();
+    throttle_ = throttle.get();
+
+    throttles_.push_back(std::move(throttle));
+  }
+
+  void CreateLoaderAndStart() {
+    auto request = base::MakeUnique<ResourceRequest>();
+    request->url = GURL("http://example.org");
+    loader_ = ThrottlingURLLoader::CreateLoaderAndStart(
+        factory_.factory_ptr().get(), std::move(throttles_), 0, 0, 0,
+        std::move(request), &client_);
+    factory_.factory_ptr().FlushForTesting();
+  }
+
+  // Be the first member so it is destroyed last.
+  base::MessageLoop message_loop_;
+
+  std::unique_ptr<ThrottlingURLLoader> loader_;
+  std::vector<std::unique_ptr<URLLoaderThrottle>> throttles_;
+
+  TestURLLoaderFactory factory_;
+  TestURLLoaderClient client_;
+
+  // Owned by |throttles_| or |loader_|.
+  TestURLLoaderThrottle* throttle_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(ThrottlingURLLoaderTest);
+};
+
+TEST_F(ThrottlingURLLoaderTest, CancelBeforeStart) {
+  throttle_->set_will_start_request_callback(
+      base::Bind([](URLLoaderThrottle::Delegate* delegate, bool* defer) {
+        delegate->CancelWithError(net::ERR_ACCESS_DENIED);
+      }));
+
+  base::RunLoop run_loop;
+  client_.set_on_complete_callback(base::Bind(
+      [](const base::Closure& quit_closure, int error) {
+        EXPECT_EQ(net::ERR_ACCESS_DENIED, error);
+        quit_closure.Run();
+      },
+      run_loop.QuitClosure()));
+
+  CreateLoaderAndStart();
+  run_loop.Run();
+
+  EXPECT_EQ(1u, throttle_->will_start_request_called());
+  EXPECT_EQ(0u, throttle_->will_redirect_request_called());
+  EXPECT_EQ(0u, throttle_->will_process_response_called());
+
+  EXPECT_EQ(0u, factory_.create_loader_and_start_called());
+
+  EXPECT_EQ(0u, client_.on_received_response_called());
+  EXPECT_EQ(0u, client_.on_received_redirect_called());
+  EXPECT_EQ(1u, client_.on_complete_called());
+}
+
+TEST_F(ThrottlingURLLoaderTest, DeferBeforeStart) {
+  throttle_->set_will_start_request_callback(
+      base::Bind([](URLLoaderThrottle::Delegate* delegate, bool* defer) {
+        *defer = true;
+      }));
+
+  base::RunLoop run_loop;
+  client_.set_on_complete_callback(base::Bind(
+      [](const base::Closure& quit_closure, int error) {
+        EXPECT_EQ(net::OK, error);
+        quit_closure.Run();
+      },
+      run_loop.QuitClosure()));
+
+  CreateLoaderAndStart();
+
+  EXPECT_EQ(1u, throttle_->will_start_request_called());
+  EXPECT_EQ(0u, throttle_->will_redirect_request_called());
+  EXPECT_EQ(0u, throttle_->will_process_response_called());
+
+  EXPECT_EQ(0u, factory_.create_loader_and_start_called());
+
+  EXPECT_EQ(0u, client_.on_received_response_called());
+  EXPECT_EQ(0u, client_.on_received_redirect_called());
+  EXPECT_EQ(0u, client_.on_complete_called());
+
+  throttle_->delegate()->Resume();
+  factory_.factory_ptr().FlushForTesting();
+
+  EXPECT_EQ(1u, factory_.create_loader_and_start_called());
+
+  factory_.NotifyClientOnReceiveResponse();
+  factory_.NotifyClientOnComplete(net::OK);
+
+  run_loop.Run();
+
+  EXPECT_EQ(1u, throttle_->will_start_request_called());
+  EXPECT_EQ(0u, throttle_->will_redirect_request_called());
+  EXPECT_EQ(1u, throttle_->will_process_response_called());
+
+  EXPECT_EQ(1u, client_.on_received_response_called());
+  EXPECT_EQ(0u, client_.on_received_redirect_called());
+  EXPECT_EQ(1u, client_.on_complete_called());
+}
+
+TEST_F(ThrottlingURLLoaderTest, CancelBeforeRedirect) {
+  throttle_->set_will_redirect_request_callback(
+      base::Bind([](URLLoaderThrottle::Delegate* delegate, bool* defer) {
+        delegate->CancelWithError(net::ERR_ACCESS_DENIED);
+      }));
+
+  base::RunLoop run_loop;
+  client_.set_on_complete_callback(base::Bind(
+      [](const base::Closure& quit_closure, int error) {
+        EXPECT_EQ(net::ERR_ACCESS_DENIED, error);
+        quit_closure.Run();
+      },
+      run_loop.QuitClosure()));
+
+  CreateLoaderAndStart();
+
+  factory_.NotifyClientOnReceiveRedirect();
+
+  run_loop.Run();
+
+  EXPECT_EQ(1u, throttle_->will_start_request_called());
+  EXPECT_EQ(1u, throttle_->will_redirect_request_called());
+  EXPECT_EQ(0u, throttle_->will_process_response_called());
+
+  EXPECT_EQ(0u, client_.on_received_response_called());
+  EXPECT_EQ(0u, client_.on_received_redirect_called());
+  EXPECT_EQ(1u, client_.on_complete_called());
+}
+
+TEST_F(ThrottlingURLLoaderTest, DeferBeforeRedirect) {
+  base::RunLoop run_loop1;
+  throttle_->set_will_redirect_request_callback(base::Bind(
+      [](const base::Closure& quit_closure,
+         URLLoaderThrottle::Delegate* delegate, bool* defer) {
+        *defer = true;
+        quit_closure.Run();
+      },
+      run_loop1.QuitClosure()));
+
+  base::RunLoop run_loop2;
+  client_.set_on_complete_callback(base::Bind(
+      [](const base::Closure& quit_closure, int error) {
+        EXPECT_EQ(net::ERR_UNEXPECTED, error);
+        quit_closure.Run();
+      },
+      run_loop2.QuitClosure()));
+
+  CreateLoaderAndStart();
+
+  factory_.NotifyClientOnReceiveRedirect();
+
+  run_loop1.Run();
+
+  EXPECT_EQ(1u, throttle_->will_start_request_called());
+  EXPECT_EQ(1u, throttle_->will_redirect_request_called());
+  EXPECT_EQ(0u, throttle_->will_process_response_called());
+
+  factory_.NotifyClientOnComplete(net::ERR_UNEXPECTED);
+
+  base::RunLoop run_loop3;
+  run_loop3.RunUntilIdle();
+
+  EXPECT_EQ(0u, client_.on_received_response_called());
+  EXPECT_EQ(0u, client_.on_received_redirect_called());
+  EXPECT_EQ(0u, client_.on_complete_called());
+
+  throttle_->delegate()->Resume();
+  run_loop2.Run();
+
+  EXPECT_EQ(1u, throttle_->will_start_request_called());
+  EXPECT_EQ(1u, throttle_->will_redirect_request_called());
+  EXPECT_EQ(0u, throttle_->will_process_response_called());
+
+  EXPECT_EQ(0u, client_.on_received_response_called());
+  EXPECT_EQ(1u, client_.on_received_redirect_called());
+  EXPECT_EQ(1u, client_.on_complete_called());
+}
+
+TEST_F(ThrottlingURLLoaderTest, CancelBeforeResponse) {
+  throttle_->set_will_process_response_callback(
+      base::Bind([](URLLoaderThrottle::Delegate* delegate, bool* defer) {
+        delegate->CancelWithError(net::ERR_ACCESS_DENIED);
+      }));
+
+  base::RunLoop run_loop;
+  client_.set_on_complete_callback(base::Bind(
+      [](const base::Closure& quit_closure, int error) {
+        EXPECT_EQ(net::ERR_ACCESS_DENIED, error);
+        quit_closure.Run();
+      },
+      run_loop.QuitClosure()));
+
+  CreateLoaderAndStart();
+
+  factory_.NotifyClientOnReceiveResponse();
+
+  run_loop.Run();
+
+  EXPECT_EQ(1u, throttle_->will_start_request_called());
+  EXPECT_EQ(0u, throttle_->will_redirect_request_called());
+  EXPECT_EQ(1u, throttle_->will_process_response_called());
+
+  EXPECT_EQ(0u, client_.on_received_response_called());
+  EXPECT_EQ(0u, client_.on_received_redirect_called());
+  EXPECT_EQ(1u, client_.on_complete_called());
+}
+
+TEST_F(ThrottlingURLLoaderTest, DeferBeforeResponse) {
+  base::RunLoop run_loop1;
+  throttle_->set_will_process_response_callback(base::Bind(
+      [](const base::Closure& quit_closure,
+         URLLoaderThrottle::Delegate* delegate, bool* defer) {
+        *defer = true;
+        quit_closure.Run();
+      },
+      run_loop1.QuitClosure()));
+
+  base::RunLoop run_loop2;
+  client_.set_on_complete_callback(base::Bind(
+      [](const base::Closure& quit_closure, int error) {
+        EXPECT_EQ(net::ERR_UNEXPECTED, error);
+        quit_closure.Run();
+      },
+      run_loop2.QuitClosure()));
+
+  CreateLoaderAndStart();
+
+  factory_.NotifyClientOnReceiveResponse();
+
+  run_loop1.Run();
+
+  EXPECT_EQ(1u, throttle_->will_start_request_called());
+  EXPECT_EQ(0u, throttle_->will_redirect_request_called());
+  EXPECT_EQ(1u, throttle_->will_process_response_called());
+
+  factory_.NotifyClientOnComplete(net::ERR_UNEXPECTED);
+
+  base::RunLoop run_loop3;
+  run_loop3.RunUntilIdle();
+
+  EXPECT_EQ(0u, client_.on_received_response_called());
+  EXPECT_EQ(0u, client_.on_received_redirect_called());
+  EXPECT_EQ(0u, client_.on_complete_called());
+
+  throttle_->delegate()->Resume();
+  run_loop2.Run();
+
+  EXPECT_EQ(1u, throttle_->will_start_request_called());
+  EXPECT_EQ(0u, throttle_->will_redirect_request_called());
+  EXPECT_EQ(1u, throttle_->will_process_response_called());
+
+  EXPECT_EQ(1u, client_.on_received_response_called());
+  EXPECT_EQ(0u, client_.on_received_redirect_called());
+  EXPECT_EQ(1u, client_.on_complete_called());
+}
+
+TEST_F(ThrottlingURLLoaderTest, ResumeNoOpIfNotDeferred) {
+  auto resume_callback =
+      base::Bind([](URLLoaderThrottle::Delegate* delegate, bool* defer) {
+        delegate->Resume();
+        delegate->Resume();
+      });
+  throttle_->set_will_start_request_callback(resume_callback);
+  throttle_->set_will_redirect_request_callback(resume_callback);
+  throttle_->set_will_process_response_callback(resume_callback);
+
+  base::RunLoop run_loop;
+  client_.set_on_complete_callback(base::Bind(
+      [](const base::Closure& quit_closure, int error) {
+        EXPECT_EQ(net::OK, error);
+        quit_closure.Run();
+      },
+      run_loop.QuitClosure()));
+
+  CreateLoaderAndStart();
+  factory_.NotifyClientOnReceiveRedirect();
+  factory_.NotifyClientOnReceiveResponse();
+  factory_.NotifyClientOnComplete(net::OK);
+
+  run_loop.Run();
+
+  EXPECT_EQ(1u, throttle_->will_start_request_called());
+  EXPECT_EQ(1u, throttle_->will_redirect_request_called());
+  EXPECT_EQ(1u, throttle_->will_process_response_called());
+
+  EXPECT_EQ(1u, client_.on_received_response_called());
+  EXPECT_EQ(1u, client_.on_received_redirect_called());
+  EXPECT_EQ(1u, client_.on_complete_called());
+}
+
+TEST_F(ThrottlingURLLoaderTest, CancelNoOpIfAlreadyCanceled) {
+  throttle_->set_will_start_request_callback(
+      base::Bind([](URLLoaderThrottle::Delegate* delegate, bool* defer) {
+        delegate->CancelWithError(net::ERR_ACCESS_DENIED);
+        delegate->CancelWithError(net::ERR_UNEXPECTED);
+      }));
+
+  base::RunLoop run_loop;
+  client_.set_on_complete_callback(base::Bind(
+      [](const base::Closure& quit_closure, int error) {
+        EXPECT_EQ(net::ERR_ACCESS_DENIED, error);
+        quit_closure.Run();
+      },
+      run_loop.QuitClosure()));
+
+  CreateLoaderAndStart();
+  throttle_->delegate()->CancelWithError(net::ERR_INVALID_ARGUMENT);
+  run_loop.Run();
+
+  EXPECT_EQ(1u, throttle_->will_start_request_called());
+  EXPECT_EQ(0u, throttle_->will_redirect_request_called());
+  EXPECT_EQ(0u, throttle_->will_process_response_called());
+
+  EXPECT_EQ(0u, factory_.create_loader_and_start_called());
+
+  EXPECT_EQ(0u, client_.on_received_response_called());
+  EXPECT_EQ(0u, client_.on_received_redirect_called());
+  EXPECT_EQ(1u, client_.on_complete_called());
+}
+
+TEST_F(ThrottlingURLLoaderTest, ResumeNoOpIfAlreadyCanceled) {
+  throttle_->set_will_process_response_callback(
+      base::Bind([](URLLoaderThrottle::Delegate* delegate, bool* defer) {
+        delegate->CancelWithError(net::ERR_ACCESS_DENIED);
+        delegate->Resume();
+      }));
+
+  base::RunLoop run_loop1;
+  client_.set_on_complete_callback(base::Bind(
+      [](const base::Closure& quit_closure, int error) {
+        EXPECT_EQ(net::ERR_ACCESS_DENIED, error);
+        quit_closure.Run();
+      },
+      run_loop1.QuitClosure()));
+
+  CreateLoaderAndStart();
+
+  factory_.NotifyClientOnReceiveResponse();
+
+  run_loop1.Run();
+
+  throttle_->delegate()->Resume();
+
+  base::RunLoop run_loop2;
+  run_loop2.RunUntilIdle();
+
+  EXPECT_EQ(1u, throttle_->will_start_request_called());
+  EXPECT_EQ(0u, throttle_->will_redirect_request_called());
+  EXPECT_EQ(1u, throttle_->will_process_response_called());
+
+  EXPECT_EQ(0u, client_.on_received_response_called());
+  EXPECT_EQ(0u, client_.on_received_redirect_called());
+  EXPECT_EQ(1u, client_.on_complete_called());
+}
+
+}  // namespace
+}  // namespace content
diff --git a/content/child/url_loader_client_impl_unittest.cc b/content/child/url_loader_client_impl_unittest.cc
index 92ce894..8f56588 100644
--- a/content/child/url_loader_client_impl_unittest.cc
+++ b/content/child/url_loader_client_impl_unittest.cc
@@ -33,7 +33,9 @@
         base::MakeUnique<TestRequestPeer>(dispatcher_.get(),
                                           &request_peer_context_),
         blink::WebURLRequest::LoadingIPCType::kMojo,
-        url_loader_factory_proxy_.get(), mojo::ScopedDataPipeConsumerHandle());
+        url_loader_factory_proxy_.get(),
+        std::vector<std::unique_ptr<URLLoaderThrottle>>(),
+        mojo::ScopedDataPipeConsumerHandle());
     request_peer_context_.request_id = request_id_;
 
     base::RunLoop().RunUntilIdle();
diff --git a/content/child/url_response_body_consumer_unittest.cc b/content/child/url_response_body_consumer_unittest.cc
index e5963e3c5a..be64d79 100644
--- a/content/child/url_response_body_consumer_unittest.cc
+++ b/content/child/url_response_body_consumer_unittest.cc
@@ -141,6 +141,7 @@
         std::move(request), 0, nullptr, url::Origin(),
         base::MakeUnique<TestRequestPeer>(context, message_loop_.task_runner()),
         blink::WebURLRequest::LoadingIPCType::kChromeIPC, nullptr,
+        std::vector<std::unique_ptr<URLLoaderThrottle>>(),
         mojo::ScopedDataPipeConsumerHandle());
   }
 
diff --git a/content/child/web_url_loader_impl.cc b/content/child/web_url_loader_impl.cc
index 73e4dee6..acd699d 100644
--- a/content/child/web_url_loader_impl.cc
+++ b/content/child/web_url_loader_impl.cc
@@ -627,8 +627,8 @@
     base::debug::DumpWithoutCrashing();
   }
 
-  const RequestExtraData empty_extra_data;
-  const RequestExtraData* extra_data;
+  RequestExtraData empty_extra_data;
+  RequestExtraData* extra_data;
   if (request.GetExtraData())
     extra_data = static_cast<RequestExtraData*>(request.GetExtraData());
   else
@@ -641,7 +641,8 @@
     DCHECK(defers_loading_ == NOT_DEFERRING);
     resource_dispatcher_->StartSync(
         std::move(resource_request), request.RequestorID(), sync_load_response,
-        request.GetLoadingIPCType(), url_loader_factory_);
+        request.GetLoadingIPCType(), url_loader_factory_,
+        extra_data->TakeURLLoaderThrottles());
     return;
   }
 
@@ -652,7 +653,7 @@
       extra_data->frame_origin(),
       base::MakeUnique<WebURLLoaderImpl::RequestPeerImpl>(this),
       request.GetLoadingIPCType(), url_loader_factory_,
-      std::move(consumer_handle));
+      extra_data->TakeURLLoaderThrottles(), std::move(consumer_handle));
 
   if (defers_loading_ != NOT_DEFERRING)
     resource_dispatcher_->SetDefersLoading(request_id_, true);
diff --git a/content/child/web_url_loader_impl_unittest.cc b/content/child/web_url_loader_impl_unittest.cc
index f0ff747..1c4c9cb7 100644
--- a/content/child/web_url_loader_impl_unittest.cc
+++ b/content/child/web_url_loader_impl_unittest.cc
@@ -67,11 +67,13 @@
 
   // TestDispatcher implementation:
 
-  void StartSync(std::unique_ptr<ResourceRequest> request,
-                 int routing_id,
-                 SyncLoadResponse* response,
-                 blink::WebURLRequest::LoadingIPCType ipc_type,
-                 mojom::URLLoaderFactory* url_loader_factory) override {
+  void StartSync(
+      std::unique_ptr<ResourceRequest> request,
+      int routing_id,
+      SyncLoadResponse* response,
+      blink::WebURLRequest::LoadingIPCType ipc_type,
+      mojom::URLLoaderFactory* url_loader_factory,
+      std::vector<std::unique_ptr<URLLoaderThrottle>> throttles) override {
     *response = sync_load_response_;
   }
 
@@ -83,6 +85,7 @@
       std::unique_ptr<RequestPeer> peer,
       blink::WebURLRequest::LoadingIPCType ipc_type,
       mojom::URLLoaderFactory* url_loader_factory,
+      std::vector<std::unique_ptr<URLLoaderThrottle>> throttles,
       mojo::ScopedDataPipeConsumerHandle consumer_handle) override {
     EXPECT_FALSE(peer_);
     peer_ = std::move(peer);
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index 144e2a2..f1bcce28 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -204,6 +204,8 @@
     "inter_process_time_ticks_converter.h",
     "layer_tree_settings_factory.cc",
     "layer_tree_settings_factory.h",
+    "mac/app_nap_activity.h",
+    "mac/app_nap_activity.mm",
     "mac/attributed_string_coder.h",
     "mac/attributed_string_coder.mm",
     "mac/font_descriptor.h",
diff --git a/content/common/mac/app_nap_activity.h b/content/common/mac/app_nap_activity.h
new file mode 100644
index 0000000..c07f9ee8
--- /dev/null
+++ b/content/common/mac/app_nap_activity.h
@@ -0,0 +1,45 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_COMMON_MAC_APP_NAP_ACTIVITY_H
+#define CONTENT_COMMON_MAC_APP_NAP_ACTIVITY_H
+
+#include <memory>
+
+#include "base/macros.h"
+#include "content/common/content_export.h"
+
+namespace content {
+
+// Can't import scoped_nsobject here, so wrap it.
+struct AssertionWrapper;
+
+// A wrapper around the macOS "activity" system, which is required to
+// make renderers eligible for AppNap.
+//
+// When doing work, processes are expected to begin an activity, receiving
+// an opaque token called an "assertion". On finishing, they end the activity.
+// When a process has no outstanding assertions, it becomes eligible for
+// AppNap.
+class CONTENT_EXPORT AppNapActivity {
+ public:
+  AppNapActivity();
+  ~AppNapActivity();
+
+  // Begin an activity and store the provided token.
+  void Begin();
+
+  // End the activity represented by |assertion_|.
+  void End();
+
+ private:
+  // An opaque token provided by the OS on beginning an activity.
+  std::unique_ptr<AssertionWrapper> assertion_;
+
+  DISALLOW_COPY_AND_ASSIGN(AppNapActivity);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_COMMON_MAC_APP_NAP_ACTIVITY_H
diff --git a/content/common/mac/app_nap_activity.mm b/content/common/mac/app_nap_activity.mm
new file mode 100644
index 0000000..d2c82e8
--- /dev/null
+++ b/content/common/mac/app_nap_activity.mm
@@ -0,0 +1,50 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/common/mac/app_nap_activity.h"
+
+#import <Foundation/Foundation.h>
+
+#include "base/mac/scoped_nsobject.h"
+
+namespace content {
+
+namespace {
+
+NSString* const kActivityReason = @"Process foregrounded";
+const NSActivityOptions kActivityOptions =
+    (NSActivityUserInitiatedAllowingIdleSystemSleep |
+     NSActivityLatencyCritical) &
+    ~(NSActivitySuddenTerminationDisabled |
+      NSActivityAutomaticTerminationDisabled);
+
+}  // namespace
+
+struct AssertionWrapper {
+  base::scoped_nsobject<id> obj;
+};
+
+AppNapActivity::AppNapActivity() {
+  assertion_.reset(new AssertionWrapper());
+};
+
+AppNapActivity::~AppNapActivity() {
+  DCHECK(!assertion_->obj.get());
+};
+
+void AppNapActivity::Begin() {
+  DCHECK(!assertion_->obj.get());
+  id assertion =
+      [[NSProcessInfo processInfo] beginActivityWithOptions:kActivityOptions
+                                                     reason:kActivityReason];
+  assertion_->obj.reset([assertion retain]);
+}
+
+void AppNapActivity::End() {
+  id assertion = assertion_->obj.autorelease();
+  DCHECK(assertion);
+  [[NSProcessInfo processInfo] endActivity:assertion];
+}
+
+}  // namespace content
diff --git a/content/common/mac/app_nap_activity_unittest.mm b/content/common/mac/app_nap_activity_unittest.mm
new file mode 100644
index 0000000..b6c36739
--- /dev/null
+++ b/content/common/mac/app_nap_activity_unittest.mm
@@ -0,0 +1,38 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/common/mac/app_nap_activity.h"
+
+#include "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+#import "third_party/ocmock/OCMock/OCMock.h"
+#include "third_party/ocmock/gtest_support.h"
+
+class AppNapActivityTest : public PlatformTest {};
+
+TEST_F(AppNapActivityTest, StoresAssertion) {
+  const NSActivityOptions expectedOptions =
+      (NSActivityUserInitiatedAllowingIdleSystemSleep |
+       NSActivityLatencyCritical) &
+      ~(NSActivitySuddenTerminationDisabled |
+        NSActivityAutomaticTerminationDisabled);
+  id processInfoMock =
+      [OCMockObject partialMockForObject:[NSProcessInfo processInfo]];
+  id assertion = @"An activity assertion";
+  [[[processInfoMock expect] andReturn:assertion]
+      beginActivityWithOptions:expectedOptions
+                        reason:OCMOCK_ANY];
+
+  content::AppNapActivity activity;
+  activity.Begin();
+
+  EXPECT_OCMOCK_VERIFY(processInfoMock);
+
+  [[processInfoMock expect] endActivity:assertion];
+
+  activity.End();
+
+  EXPECT_OCMOCK_VERIFY(processInfoMock);
+  [processInfoMock stopMocking];
+}
diff --git a/content/public/child/BUILD.gn b/content/public/child/BUILD.gn
index 36a0155..dd0b85e 100644
--- a/content/public/child/BUILD.gn
+++ b/content/public/child/BUILD.gn
@@ -35,6 +35,7 @@
     "image_decoder_utils.h",
     "request_peer.h",
     "resource_dispatcher_delegate.h",
+    "url_loader_throttle.h",
     "v8_value_converter.h",
     "worker_thread.h",
   ]
diff --git a/content/public/child/url_loader_throttle.h b/content/public/child/url_loader_throttle.h
new file mode 100644
index 0000000..e72a4ff
--- /dev/null
+++ b/content/public/child/url_loader_throttle.h
@@ -0,0 +1,67 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_PUBLIC_RENDERER_URL_LOADER_THROTTLE_H_
+#define CONTENT_PUBLIC_RENDERER_URL_LOADER_THROTTLE_H_
+
+#include "content/common/content_export.h"
+#include "content/public/common/resource_type.h"
+
+class GURL;
+
+namespace net {
+struct RedirectInfo;
+}
+
+namespace content {
+
+// A URLLoaderThrottle gets notified at various points during the process of
+// loading a resource. At each stage, it has the opportunity to defer the
+// resource load.
+class CONTENT_EXPORT URLLoaderThrottle {
+ public:
+  // An interface for the throttle implementation to resume (when deferred) or
+  // cancel the resource load.
+  class CONTENT_EXPORT Delegate {
+   public:
+    // Cancels the resource load with the specified error code.
+    virtual void CancelWithError(int error_code) = 0;
+
+    // Resumes the deferred resource load. It is a no-op if the resource load is
+    // not deferred or has already been canceled.
+    virtual void Resume() = 0;
+
+   protected:
+    virtual ~Delegate() {}
+  };
+
+  virtual ~URLLoaderThrottle() {}
+
+  // Called before the resource request is started.
+  virtual void WillStartRequest(const GURL& url,
+                                int load_flags,
+                                ResourceType resource_type,
+                                bool* defer) {}
+
+  // Called when the request was redirected.  |redirect_info| contains the
+  // redirect responses's HTTP status code and some information about the new
+  // request that will be sent if the redirect is followed, including the new
+  // URL and new method.
+  virtual void WillRedirectRequest(const net::RedirectInfo& redirect_info,
+                                   bool* defer) {}
+
+  // Called when the response headers and meta data are available.
+  virtual void WillProcessResponse(bool* defer) {}
+
+  void set_delegate(Delegate* delegate) { delegate_ = delegate; }
+
+ protected:
+  URLLoaderThrottle() = default;
+
+  Delegate* delegate_ = nullptr;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_PUBLIC_RENDERER_URL_LOADER_THROTTLE_H_
diff --git a/content/public/common/BUILD.gn b/content/public/common/BUILD.gn
index 1539dfa..18bdf6c0 100644
--- a/content/public/common/BUILD.gn
+++ b/content/public/common/BUILD.gn
@@ -349,3 +349,9 @@
     "service_names.mojom",
   ]
 }
+
+mojom("resource_type_bindings") {
+  sources = [
+    "resource_type.mojom",
+  ]
+}
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index 22ad539..ae472d6 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -163,9 +163,6 @@
 // For tests and platforms where software fallback is disabled.
 const char kDisableGpuProcessCrashLimit[] = "disable-gpu-process-crash-limit";
 
-// Disable async GL worker context. Overrides kEnableGpuAsyncWorkerContext.
-const char kDisableGpuAsyncWorkerContext[] = "disable-gpu-async-worker-context";
-
 // When using CPU rasterizing disable low resolution tiling. This uses
 // less power, particularly during animations, but more white may be seen
 // during fast scrolling especially on slower devices.
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index 79c9571..ec1ba5e 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -53,7 +53,6 @@
 CONTENT_EXPORT extern const char kDisableFlashStage3d[];
 CONTENT_EXPORT extern const char kDisableGestureRequirementForPresentation[];
 CONTENT_EXPORT extern const char kDisableGpu[];
-CONTENT_EXPORT extern const char kDisableGpuAsyncWorkerContext[];
 CONTENT_EXPORT extern const char kDisableGpuCompositing[];
 CONTENT_EXPORT extern const char kDisableGpuEarlyInit[];
 CONTENT_EXPORT extern const char kDisableGpuMemoryBufferCompositorResources[];
diff --git a/content/public/common/resource_type.mojom b/content/public/common/resource_type.mojom
new file mode 100644
index 0000000..98211a5
--- /dev/null
+++ b/content/public/common/resource_type.mojom
@@ -0,0 +1,30 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module content.mojom;
+
+// This needs to match the definition of content::ResourceType.
+enum ResourceType {
+  RESOURCE_TYPE_MAIN_FRAME = 0,       // top level page
+  RESOURCE_TYPE_SUB_FRAME = 1,        // frame or iframe
+  RESOURCE_TYPE_STYLESHEET = 2,       // a CSS stylesheet
+  RESOURCE_TYPE_SCRIPT = 3,           // an external script
+  RESOURCE_TYPE_IMAGE = 4,            // an image (jpg/gif/png/etc)
+  RESOURCE_TYPE_FONT_RESOURCE = 5,    // a font
+  RESOURCE_TYPE_SUB_RESOURCE = 6,     // an "other" subresource.
+  RESOURCE_TYPE_OBJECT = 7,           // an object (or embed) tag for a plugin.
+  RESOURCE_TYPE_MEDIA = 8,            // a media resource.
+  RESOURCE_TYPE_WORKER = 9,           // the main resource of a dedicated
+                                      // worker.
+  RESOURCE_TYPE_SHARED_WORKER = 10,   // the main resource of a shared worker.
+  RESOURCE_TYPE_PREFETCH = 11,        // an explicitly requested prefetch
+  RESOURCE_TYPE_FAVICON = 12,         // a favicon
+  RESOURCE_TYPE_XHR = 13,             // a XMLHttpRequest
+  RESOURCE_TYPE_PING = 14,            // a ping request for <a ping>/sendBeacon.
+  RESOURCE_TYPE_SERVICE_WORKER = 15,  // the main resource of a service worker.
+  RESOURCE_TYPE_CSP_REPORT = 16,      // a report of Content Security Policy
+                                      // violations.
+  RESOURCE_TYPE_PLUGIN_RESOURCE = 17, // a resource that a plugin requested.
+  RESOURCE_TYPE_LAST_TYPE
+};
diff --git a/content/public/common/resource_type.typemap b/content/public/common/resource_type.typemap
new file mode 100644
index 0000000..5a890062
--- /dev/null
+++ b/content/public/common/resource_type.typemap
@@ -0,0 +1,14 @@
+# Copyright 2017 The Chromium 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 = "//content/public/common/resource_type.mojom"
+public_headers = [ "//content/public/common/resource_type.h" ]
+traits_headers = [ "//content/public/common/resource_type_enum_traits.h" ]
+sources = [
+  "//content/public/common/resource_type_enum_traits.cc",
+]
+deps = [
+  "//content:export",
+]
+type_mappings = [ "content.mojom.ResourceType=content::ResourceType" ]
diff --git a/content/public/common/resource_type_enum_traits.cc b/content/public/common/resource_type_enum_traits.cc
new file mode 100644
index 0000000..cb3fc2cc
--- /dev/null
+++ b/content/public/common/resource_type_enum_traits.cc
@@ -0,0 +1,124 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/public/common/resource_type_enum_traits.h"
+
+namespace mojo {
+
+// static
+content::mojom::ResourceType
+EnumTraits<content::mojom::ResourceType, content::ResourceType>::ToMojom(
+    content::ResourceType input) {
+  switch (input) {
+    case content::RESOURCE_TYPE_MAIN_FRAME:
+      return content::mojom::ResourceType::RESOURCE_TYPE_MAIN_FRAME;
+    case content::RESOURCE_TYPE_SUB_FRAME:
+      return content::mojom::ResourceType::RESOURCE_TYPE_SUB_FRAME;
+    case content::RESOURCE_TYPE_STYLESHEET:
+      return content::mojom::ResourceType::RESOURCE_TYPE_STYLESHEET;
+    case content::RESOURCE_TYPE_SCRIPT:
+      return content::mojom::ResourceType::RESOURCE_TYPE_SCRIPT;
+    case content::RESOURCE_TYPE_IMAGE:
+      return content::mojom::ResourceType::RESOURCE_TYPE_IMAGE;
+    case content::RESOURCE_TYPE_FONT_RESOURCE:
+      return content::mojom::ResourceType::RESOURCE_TYPE_FONT_RESOURCE;
+    case content::RESOURCE_TYPE_SUB_RESOURCE:
+      return content::mojom::ResourceType::RESOURCE_TYPE_SUB_RESOURCE;
+    case content::RESOURCE_TYPE_OBJECT:
+      return content::mojom::ResourceType::RESOURCE_TYPE_OBJECT;
+    case content::RESOURCE_TYPE_MEDIA:
+      return content::mojom::ResourceType::RESOURCE_TYPE_MEDIA;
+    case content::RESOURCE_TYPE_WORKER:
+      return content::mojom::ResourceType::RESOURCE_TYPE_WORKER;
+    case content::RESOURCE_TYPE_SHARED_WORKER:
+      return content::mojom::ResourceType::RESOURCE_TYPE_SHARED_WORKER;
+    case content::RESOURCE_TYPE_PREFETCH:
+      return content::mojom::ResourceType::RESOURCE_TYPE_PREFETCH;
+    case content::RESOURCE_TYPE_FAVICON:
+      return content::mojom::ResourceType::RESOURCE_TYPE_FAVICON;
+    case content::RESOURCE_TYPE_XHR:
+      return content::mojom::ResourceType::RESOURCE_TYPE_XHR;
+    case content::RESOURCE_TYPE_PING:
+      return content::mojom::ResourceType::RESOURCE_TYPE_PING;
+    case content::RESOURCE_TYPE_SERVICE_WORKER:
+      return content::mojom::ResourceType::RESOURCE_TYPE_SERVICE_WORKER;
+    case content::RESOURCE_TYPE_CSP_REPORT:
+      return content::mojom::ResourceType::RESOURCE_TYPE_CSP_REPORT;
+    case content::RESOURCE_TYPE_PLUGIN_RESOURCE:
+      return content::mojom::ResourceType::RESOURCE_TYPE_PLUGIN_RESOURCE;
+    case content::RESOURCE_TYPE_LAST_TYPE:
+      return content::mojom::ResourceType::RESOURCE_TYPE_LAST_TYPE;
+  }
+
+  NOTREACHED();
+  return content::mojom::ResourceType::RESOURCE_TYPE_MAIN_FRAME;
+}
+// static
+bool EnumTraits<content::mojom::ResourceType, content::ResourceType>::FromMojom(
+
+    content::mojom::ResourceType input,
+    content::ResourceType* output) {
+  switch (input) {
+    case content::mojom::ResourceType::RESOURCE_TYPE_MAIN_FRAME:
+      *output = content::RESOURCE_TYPE_MAIN_FRAME;
+      return true;
+    case content::mojom::ResourceType::RESOURCE_TYPE_SUB_FRAME:
+      *output = content::RESOURCE_TYPE_SUB_FRAME;
+      return true;
+    case content::mojom::ResourceType::RESOURCE_TYPE_STYLESHEET:
+      *output = content::RESOURCE_TYPE_STYLESHEET;
+      return true;
+    case content::mojom::ResourceType::RESOURCE_TYPE_SCRIPT:
+      *output = content::RESOURCE_TYPE_SCRIPT;
+      return true;
+    case content::mojom::ResourceType::RESOURCE_TYPE_IMAGE:
+      *output = content::RESOURCE_TYPE_IMAGE;
+      return true;
+    case content::mojom::ResourceType::RESOURCE_TYPE_FONT_RESOURCE:
+      *output = content::RESOURCE_TYPE_FONT_RESOURCE;
+      return true;
+    case content::mojom::ResourceType::RESOURCE_TYPE_SUB_RESOURCE:
+      *output = content::RESOURCE_TYPE_SUB_RESOURCE;
+      return true;
+    case content::mojom::ResourceType::RESOURCE_TYPE_OBJECT:
+      *output = content::RESOURCE_TYPE_OBJECT;
+      return true;
+    case content::mojom::ResourceType::RESOURCE_TYPE_MEDIA:
+      *output = content::RESOURCE_TYPE_MEDIA;
+      return true;
+    case content::mojom::ResourceType::RESOURCE_TYPE_WORKER:
+      *output = content::RESOURCE_TYPE_WORKER;
+      return true;
+    case content::mojom::ResourceType::RESOURCE_TYPE_SHARED_WORKER:
+      *output = content::RESOURCE_TYPE_SHARED_WORKER;
+      return true;
+    case content::mojom::ResourceType::RESOURCE_TYPE_PREFETCH:
+      *output = content::RESOURCE_TYPE_PREFETCH;
+      return true;
+    case content::mojom::ResourceType::RESOURCE_TYPE_FAVICON:
+      *output = content::RESOURCE_TYPE_FAVICON;
+      return true;
+    case content::mojom::ResourceType::RESOURCE_TYPE_XHR:
+      *output = content::RESOURCE_TYPE_XHR;
+      return true;
+    case content::mojom::ResourceType::RESOURCE_TYPE_PING:
+      *output = content::RESOURCE_TYPE_PING;
+      return true;
+    case content::mojom::ResourceType::RESOURCE_TYPE_SERVICE_WORKER:
+      *output = content::RESOURCE_TYPE_SERVICE_WORKER;
+      return true;
+    case content::mojom::ResourceType::RESOURCE_TYPE_CSP_REPORT:
+      *output = content::RESOURCE_TYPE_CSP_REPORT;
+      return true;
+    case content::mojom::ResourceType::RESOURCE_TYPE_PLUGIN_RESOURCE:
+      *output = content::RESOURCE_TYPE_PLUGIN_RESOURCE;
+      return true;
+    case content::mojom::ResourceType::RESOURCE_TYPE_LAST_TYPE:
+      *output = content::RESOURCE_TYPE_LAST_TYPE;
+      return true;
+  }
+  return false;
+}
+
+}  // namespace mojo
diff --git a/content/public/common/resource_type_enum_traits.h b/content/public/common/resource_type_enum_traits.h
new file mode 100644
index 0000000..e458c65
--- /dev/null
+++ b/content/public/common/resource_type_enum_traits.h
@@ -0,0 +1,22 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_PUBLIC_COMMON_RESOURCE_TYPE_ENUM_TRAITS_H_
+#define CONTENT_PUBLIC_COMMON_RESOURCE_TYPE_ENUM_TRAITS_H_
+
+#include "content/public/common/resource_type.h"
+#include "content/public/common/resource_type.mojom-shared.h"
+#include "mojo/public/cpp/bindings/enum_traits.h"
+
+namespace mojo {
+
+template <>
+struct EnumTraits<content::mojom::ResourceType, content::ResourceType> {
+  static content::mojom::ResourceType ToMojom(content::ResourceType input);
+  static bool FromMojom(content::mojom::ResourceType input,
+                        content::ResourceType* output);
+};
+}
+
+#endif  // CONTENT_PUBLIC_COMMON_RESOURCE_TYPE_ENUM_TRAITS_H_
diff --git a/content/public/common/typemaps.gni b/content/public/common/typemaps.gni
index 9e064ca..a795fa0e 100644
--- a/content/public/common/typemaps.gni
+++ b/content/public/common/typemaps.gni
@@ -2,4 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-typemaps = [ "//content/public/common/referrer.typemap" ]
+typemaps = [
+  "//content/public/common/referrer.typemap",
+  "//content/public/common/resource_type.typemap",
+]
diff --git a/content/public/renderer/content_renderer_client.cc b/content/public/renderer/content_renderer_client.cc
index 02565ee..5d510fe 100644
--- a/content/public/renderer/content_renderer_client.cc
+++ b/content/public/renderer/content_renderer_client.cc
@@ -131,10 +131,12 @@
   return false;
 }
 
-bool ContentRendererClient::WillSendRequest(blink::WebLocalFrame* frame,
-                                            ui::PageTransition transition_type,
-                                            const blink::WebURL& url,
-                                            GURL* new_url) {
+bool ContentRendererClient::WillSendRequest(
+    blink::WebLocalFrame* frame,
+    ui::PageTransition transition_type,
+    const blink::WebURL& url,
+    std::vector<std::unique_ptr<URLLoaderThrottle>>* throttles,
+    GURL* new_url) {
   return false;
 }
 
diff --git a/content/public/renderer/content_renderer_client.h b/content/public/renderer/content_renderer_client.h
index 0e554ba..7a3ecf5 100644
--- a/content/public/renderer/content_renderer_client.h
+++ b/content/public/renderer/content_renderer_client.h
@@ -66,6 +66,7 @@
 class MediaStreamRendererFactory;
 class RenderFrame;
 class RenderView;
+class URLLoaderThrottle;
 
 // Embedder API for participating in renderer logic.
 class CONTENT_EXPORT ContentRendererClient {
@@ -223,11 +224,15 @@
                           bool* send_referrer);
 
   // Notifies the embedder that the given frame is requesting the resource at
-  // |url|.  If the function returns true, the url is changed to |new_url|.
-  virtual bool WillSendRequest(blink::WebLocalFrame* frame,
-                               ui::PageTransition transition_type,
-                               const blink::WebURL& url,
-                               GURL* new_url);
+  // |url|. |throttles| is appended with URLLoaderThrottle instances that should
+  // be applied to the resource loading. It is only used when network service is
+  // enabled. If the function returns true, the url is changed to |new_url|.
+  virtual bool WillSendRequest(
+      blink::WebLocalFrame* frame,
+      ui::PageTransition transition_type,
+      const blink::WebURL& url,
+      std::vector<std::unique_ptr<URLLoaderThrottle>>* throttles,
+      GURL* new_url);
 
   // Returns true if the request is associated with a document that is in
   // ""prefetch only" mode, and will not be rendered.
diff --git a/content/renderer/accessibility/blink_ax_enum_conversion.cc b/content/renderer/accessibility/blink_ax_enum_conversion.cc
index 21f7930c..26d72eb 100644
--- a/content/renderer/accessibility/blink_ax_enum_conversion.cc
+++ b/content/renderer/accessibility/blink_ax_enum_conversion.cc
@@ -43,9 +43,6 @@
   if (o.IsOffScreen())
     state |= (1 << ui::AX_STATE_OFFSCREEN);
 
-  if (o.IsPressed())
-    state |= (1 << ui::AX_STATE_PRESSED);
-
   if (o.IsPasswordField())
     state |= (1 << ui::AX_STATE_PROTECTED);
 
@@ -528,15 +525,17 @@
 ui::AXCheckedState AXCheckedStateFromBlink(
     blink::WebAXCheckedState checked_state) {
   switch (checked_state) {
-    case blink::WebAXCheckedFalse:
-      return ui::AX_CHECKED_STATE_FALSE;
-    case blink::WebAXCheckedTrue:
+    case blink::kWebAXCheckedUndefined:
+      return ui::AX_CHECKED_STATE_NONE;
+    case blink::kWebAXCheckedTrue:
       return ui::AX_CHECKED_STATE_TRUE;
-    case blink::WebAXCheckedMixed:
+    case blink::kWebAXCheckedMixed:
       return ui::AX_CHECKED_STATE_MIXED;
+    case blink::kWebAXCheckedFalse:
+      return ui::AX_CHECKED_STATE_FALSE;
   }
   NOTREACHED();
-  return ui::AX_CHECKED_STATE_FALSE;
+  return ui::AX_CHECKED_STATE_NONE;
 }
 
 ui::AXSortDirection AXSortDirectionFromBlink(
diff --git a/content/renderer/accessibility/blink_ax_tree_source.cc b/content/renderer/accessibility/blink_ax_tree_source.cc
index 8a931fb..923e639 100644
--- a/content/renderer/accessibility/blink_ax_tree_source.cc
+++ b/content/renderer/accessibility/blink_ax_tree_source.cc
@@ -493,10 +493,9 @@
                               src.AriaInvalidValue().Utf8());
     }
 
-    if (src.IsCheckable()) {
-      const blink::WebAXCheckedState checked_state = src.CheckedState();
+    if (src.CheckedState()) {
       dst->AddIntAttribute(ui::AX_ATTR_CHECKED_STATE,
-                           AXCheckedStateFromBlink(checked_state));
+                           AXCheckedStateFromBlink(src.CheckedState()));
     }
 
     if (src.GetTextDirection()) {
diff --git a/content/renderer/gpu/render_widget_compositor.cc b/content/renderer/gpu/render_widget_compositor.cc
index e979d11d..bfbf51e 100644
--- a/content/renderer/gpu/render_widget_compositor.cc
+++ b/content/renderer/gpu/render_widget_compositor.cc
@@ -66,6 +66,7 @@
 #include "third_party/WebKit/public/platform/scheduler/renderer/renderer_scheduler.h"
 #include "third_party/WebKit/public/web/WebKit.h"
 #include "third_party/WebKit/public/web/WebSelection.h"
+#include "third_party/skia/include/core/SkImage.h"
 #include "ui/gfx/switches.h"
 #include "ui/gl/gl_switches.h"
 #include "ui/native_theme/native_theme_features.h"
@@ -387,13 +388,13 @@
   settings.use_partial_raster = compositor_deps->IsPartialRasterEnabled();
   settings.enable_elastic_overscroll =
       compositor_deps->IsElasticOverscrollEnabled();
-  settings.renderer_settings.use_gpu_memory_buffer_resources =
+  settings.resource_settings.use_gpu_memory_buffer_resources =
       compositor_deps->IsGpuMemoryBufferCompositorResourcesEnabled();
   settings.enable_color_correct_rasterization =
       cmd.HasSwitch(switches::kEnableColorCorrectRendering);
   settings.renderer_settings.enable_color_correct_rendering =
       cmd.HasSwitch(switches::kEnableColorCorrectRendering);
-  settings.buffer_to_texture_target_map =
+  settings.resource_settings.buffer_to_texture_target_map =
       compositor_deps->GetBufferToTextureTargetMap();
 
   // Build LayerTreeSettings from command line args.
@@ -1096,6 +1097,23 @@
   layer_tree_host_->SetBottomControlsHeight(height);
 }
 
+void RenderWidgetCompositor::RequestDecode(
+    sk_sp<SkImage> image,
+    const base::Callback<void(bool)>& callback) {
+  layer_tree_host_->QueueImageDecode(std::move(image), callback);
+
+  // If we're compositing synchronously, the SetNeedsCommit call which will be
+  // issued by |layer_tree_host_| is not going to cause a commit, due to the
+  // fact that this would make layout tests slow and cause flakiness. However,
+  // in this case we actually need a commit to transfer the decode requests to
+  // the impl side. So, force a commit to happen.
+  if (CompositeIsSynchronous()) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(&RenderWidgetCompositor::SynchronouslyComposite,
+                              weak_factory_.GetWeakPtr()));
+  }
+}
+
 void RenderWidgetCompositor::WillBeginMainFrame() {
   delegate_->WillBeginCompositorFrame();
 }
diff --git a/content/renderer/gpu/render_widget_compositor.h b/content/renderer/gpu/render_widget_compositor.h
index a0b64ff..4640b38 100644
--- a/content/renderer/gpu/render_widget_compositor.h
+++ b/content/renderer/gpu/render_widget_compositor.h
@@ -182,6 +182,8 @@
   // TODO(ianwen): Move this method to WebLayerTreeView and implement main
   // thread scrolling.
   virtual void setBottomControlsHeight(float height);
+  void RequestDecode(sk_sp<SkImage> image,
+                     const base::Callback<void(bool)>& callback) override;
 
   // cc::LayerTreeHostClient implementation.
   void WillBeginMainFrame() override;
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 3cbb833..de85563ae 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -71,6 +71,7 @@
 #include "content/common/swapped_out_messages.h"
 #include "content/common/view_messages.h"
 #include "content/common/worker_url_loader_factory_provider.mojom.h"
+#include "content/public/child/url_loader_throttle.h"
 #include "content/public/common/appcache_info.h"
 #include "content/public/common/associated_interface_provider.h"
 #include "content/public/common/bindings_policy.h"
@@ -4189,9 +4190,10 @@
         transition_type | ui::PAGE_TRANSITION_CLIENT_REDIRECT);
   }
 
+  std::vector<std::unique_ptr<URLLoaderThrottle>> throttles;
   GURL new_url;
   if (GetContentClient()->renderer()->WillSendRequest(
-          frame_, transition_type, request.Url(), &new_url)) {
+          frame_, transition_type, request.Url(), &throttles, &new_url)) {
     request.SetURL(WebURL(new_url));
   }
 
@@ -4288,6 +4290,9 @@
   }
 
   extra_data->set_url_loader_factory_override(url_loader_factory_.get());
+  // TODO(kinuko, yzshen): We need to set up throttles for some worker cases
+  // that don't go through here.
+  extra_data->set_url_loader_throttles(std::move(throttles));
 
   request.SetExtraData(extra_data);
 
diff --git a/content/renderer/renderer_main_platform_delegate_android.cc b/content/renderer/renderer_main_platform_delegate_android.cc
index a2ece9e..fc14746 100644
--- a/content/renderer/renderer_main_platform_delegate_android.cc
+++ b/content/renderer/renderer_main_platform_delegate_android.cc
@@ -11,6 +11,7 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/metrics/histogram_macros.h"
+#include "content/public/renderer/seccomp_sandbox_status_android.h"
 #include "sandbox/sandbox_features.h"
 
 #if BUILDFLAG(USE_SECCOMP_BPF)
@@ -48,8 +49,7 @@
 #if BUILDFLAG(USE_SECCOMP_BPF)
 // Determines if the running device should support Seccomp, based on the Android
 // SDK version.
-bool IsSeccompBPFSupportedBySDK() {
-  auto* info = base::android::BuildInfo::GetInstance();
+bool IsSeccompBPFSupportedBySDK(const base::android::BuildInfo* info) {
   if (info->sdk_int() < 22) {
     // Seccomp was never available pre-Lollipop.
     return false;
@@ -91,8 +91,10 @@
   RecordSeccompStatus status_uma;
 
 #if BUILDFLAG(USE_SECCOMP_BPF)
+  auto* info = base::android::BuildInfo::GetInstance();
+
   // Determine if Seccomp is available via the Android SDK version.
-  if (!IsSeccompBPFSupportedBySDK())
+  if (!IsSeccompBPFSupportedBySDK(info))
     return true;
 
   // Do run-time detection to ensure that support is present.
@@ -108,12 +110,15 @@
   if (base::FeatureList::IsEnabled(features::kSeccompSandboxAndroid)) {
     status_uma.set_status(SeccompSandboxStatus::FEATURE_ENABLED);
 
-    // TODO(rsesek): When "the thing after N" has an sdk_int(), restrict this to
-    // that platform version or higher.
     sig_t old_handler = signal(SIGSYS, SIG_DFL);
     if (old_handler != SIG_DFL) {
-      DLOG(WARNING) << "Un-hooking existing SIGSYS handler before "
-                    << "starting Seccomp sandbox";
+      // On Android O and later, the zygote applies a seccomp filter to all
+      // apps. It has its own SIGSYS handler that must be un-hooked so that
+      // the Chromium one can be used instead. If pre-O devices have a SIGSYS
+      // handler, then warn about that.
+      DLOG_IF(WARNING, info->sdk_int() < 26)
+          << "Un-hooking existing SIGSYS handler before starting "
+          << "Seccomp sandbox";
     }
 
     sandbox::SandboxBPF sandbox(new SandboxBPFBasePolicyAndroid());
diff --git a/content/shell/test_runner/web_ax_object_proxy.cc b/content/shell/test_runner/web_ax_object_proxy.cc
index 79e403c1..5ae5dd7 100644
--- a/content/shell/test_runner/web_ax_object_proxy.cc
+++ b/content/shell/test_runner/web_ax_object_proxy.cc
@@ -605,7 +605,7 @@
       .SetProperty("isSelectedOptionActive",
                    &WebAXObjectProxy::IsSelectedOptionActive)
       .SetProperty("isExpanded", &WebAXObjectProxy::IsExpanded)
-      .SetProperty("isChecked", &WebAXObjectProxy::IsChecked)
+      .SetProperty("checked", &WebAXObjectProxy::Checked)
       .SetProperty("isVisible", &WebAXObjectProxy::IsVisible)
       .SetProperty("isOffScreen", &WebAXObjectProxy::IsOffScreen)
       .SetProperty("isCollapsed", &WebAXObjectProxy::IsCollapsed)
@@ -636,7 +636,6 @@
       .SetProperty("columnCount", &WebAXObjectProxy::ColumnCount)
       .SetProperty("columnHeadersCount", &WebAXObjectProxy::ColumnHeadersCount)
       .SetProperty("isClickable", &WebAXObjectProxy::IsClickable)
-      .SetProperty("isButtonStateMixed", &WebAXObjectProxy::IsButtonStateMixed)
       //
       // NEW bounding rect calculation - high-level interface
       //
@@ -1037,9 +1036,18 @@
   return accessibility_object_.IsExpanded() == blink::kWebAXExpandedExpanded;
 }
 
-bool WebAXObjectProxy::IsChecked() {
+std::string WebAXObjectProxy::Checked() {
   accessibility_object_.UpdateLayoutAndCheckValidity();
-  return accessibility_object_.CheckedState() != blink::WebAXCheckedFalse;
+  switch (accessibility_object_.CheckedState()) {
+    case blink::kWebAXCheckedTrue:
+      return "true";
+    case blink::kWebAXCheckedMixed:
+      return "mixed";
+    case blink::kWebAXCheckedFalse:
+      return "false";
+    default:
+      return std::string();
+  }
 }
 
 bool WebAXObjectProxy::IsCollapsed() {
@@ -1255,11 +1263,6 @@
   return accessibility_object_.IsClickable();
 }
 
-bool WebAXObjectProxy::IsButtonStateMixed() {
-  accessibility_object_.UpdateLayoutAndCheckValidity();
-  return accessibility_object_.CheckedState() == blink::WebAXCheckedMixed;
-}
-
 v8::Local<v8::Object> WebAXObjectProxy::AriaControlsElementAtIndex(
     unsigned index) {
   accessibility_object_.UpdateLayoutAndCheckValidity();
diff --git a/content/shell/test_runner/web_ax_object_proxy.h b/content/shell/test_runner/web_ax_object_proxy.h
index 9d5f0a0d..6c169c7 100644
--- a/content/shell/test_runner/web_ax_object_proxy.h
+++ b/content/shell/test_runner/web_ax_object_proxy.h
@@ -107,7 +107,7 @@
   bool IsMultiSelectable();
   bool IsSelectedOptionActive();
   bool IsExpanded();
-  bool IsChecked();
+  std::string Checked();
   bool IsVisible();
   bool IsOffScreen();
   bool IsCollapsed();
@@ -139,7 +139,6 @@
   int32_t ColumnCount();
   int32_t ColumnHeadersCount();
   bool IsClickable();
-  bool IsButtonStateMixed();
   float BoundsX();
   float BoundsY();
   float BoundsWidth();
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index b43eab8..8536ad44 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1348,6 +1348,7 @@
     "../child/site_isolation_stats_gatherer_unittest.cc",
     "../child/test_request_peer.cc",
     "../child/test_request_peer.h",
+    "../child/throttling_url_loader_unittest.cc",
     "../child/url_loader_client_impl_unittest.cc",
     "../child/url_response_body_consumer_unittest.cc",
     "../child/v8_value_converter_impl_unittest.cc",
@@ -1372,6 +1373,7 @@
     "../common/input/input_param_traits_unittest.cc",
     "../common/input/touch_event_stream_validator_unittest.cc",
     "../common/inter_process_time_ticks_converter_unittest.cc",
+    "../common/mac/app_nap_activity_unittest.mm",
     "../common/mac/attributed_string_coder_unittest.mm",
     "../common/mac/font_descriptor_unittest.mm",
     "../common/manifest_util_unittest.cc",
diff --git a/content/test/data/accessibility/aria/aria-pressed-expected-android.txt b/content/test/data/accessibility/aria/aria-pressed-expected-android.txt
index 2725bfa..4a07726 100644
--- a/content/test/data/accessibility/aria/aria-pressed-expected-android.txt
+++ b/content/test/data/accessibility/aria/aria-pressed-expected-android.txt
@@ -2,4 +2,4 @@
 ++android.widget.Button role_description='button' clickable focusable name='Regular button'
 ++android.widget.ToggleButton role_description='toggle button' checkable clickable focusable name='Toggle button unpressed'
 ++android.widget.ToggleButton role_description='toggle button' checkable checked clickable focusable name='Toggle button pressed'
-++android.widget.ToggleButton role_description='toggle button' checkable checked clickable focusable name='Toggle button mixed'
\ No newline at end of file
+++android.widget.ToggleButton role_description='toggle button' checkable clickable focusable name='Toggle button mixed'
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-pressed-expected-win.txt b/content/test/data/accessibility/aria/aria-pressed-expected-win.txt
index d14db5e8..54d497c 100644
--- a/content/test/data/accessibility/aria/aria-pressed-expected-win.txt
+++ b/content/test/data/accessibility/aria/aria-pressed-expected-win.txt
@@ -2,4 +2,4 @@
 ++ROLE_SYSTEM_PUSHBUTTON FOCUSABLE
 ++IA2_ROLE_TOGGLE_BUTTON FOCUSABLE checkable:true
 ++IA2_ROLE_TOGGLE_BUTTON PRESSED FOCUSABLE checkable:true
-++IA2_ROLE_TOGGLE_BUTTON PRESSED FOCUSABLE checkable:true
+++IA2_ROLE_TOGGLE_BUTTON MIXED FOCUSABLE checkable:true
diff --git a/content/test/data/accessibility/aria/aria-pressed.html b/content/test/data/accessibility/aria/aria-pressed.html
index 700308d..eaefc58 100644
--- a/content/test/data/accessibility/aria/aria-pressed.html
+++ b/content/test/data/accessibility/aria/aria-pressed.html
@@ -1,6 +1,7 @@
 <!--
 @WIN-DENY:name*
 @WIN-ALLOW:PRESSED
+@WIN-ALLOW:MIXED
 @WIN-ALLOW:checkable:true
 @MAC-ALLOW:AXSubrole=*
 @MAC-ALLOW:AXRoleDescription=*
diff --git a/content/test/data/accessibility/aria/aria-tree-expected-android.txt b/content/test/data/accessibility/aria/aria-tree-expected-android.txt
index 7161f6b6..4df87a11 100644
--- a/content/test/data/accessibility/aria/aria-tree-expected-android.txt
+++ b/content/test/data/accessibility/aria/aria-tree-expected-android.txt
@@ -1,10 +1,10 @@
 android.webkit.WebView focusable focused scrollable
 ++android.view.View role_description='tree' collection hierarchical row_count=2
-++++android.view.View role_description='tree item' collection_item name='Animals '
+++++android.view.View role_description='tree item' checkable collection_item name='Animals '
 ++++++android.view.View clickable name='Animals'
 ++++++android.view.View role_description='tree item' collection_item name='Domesticated ' row_index=1
 ++++++++android.view.View clickable name='Domesticated'
-++++++++android.view.View role_description='tree item' collection_item name='Dog' row_index=1
-++++++++android.view.View role_description='tree item' collection_item name='Cat' item_index=1 row_index=2
+++++++++android.view.View role_description='tree item' checkable checked collection_item name='Dog' row_index=1
+++++++++android.view.View role_description='tree item' checkable collection_item name='Cat' item_index=1 row_index=2
 ++++++android.view.View role_description='tree item' collection_item name='Wild' item_index=1 row_index=2
 ++++android.view.View role_description='tree item' collection_item name='Plants' item_index=1 row_index=1
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-tree-expected-blink.txt b/content/test/data/accessibility/aria/aria-tree-expected-blink.txt
new file mode 100644
index 0000000..13af0d8
--- /dev/null
+++ b/content/test/data/accessibility/aria/aria-tree-expected-blink.txt
@@ -0,0 +1,20 @@
+rootWebArea
+++tree
+++++treeItem name='Animals ' hierarchicalLevel=1 setSize=2 posInSet=1 checkedState=3
+++++++staticText name='Animals'
+++++++++inlineTextBox name='Animals'
+++++++treeItem name='Domesticated ' hierarchicalLevel=2 setSize=2 posInSet=1
+++++++++staticText name='Domesticated'
+++++++++++inlineTextBox name='Domesticated'
+++++++++treeItem name='Dog' hierarchicalLevel=3 setSize=2 posInSet=1 checkedState=2
+++++++++++staticText name='Dog'
+++++++++++++inlineTextBox name='Dog'
+++++++++treeItem name='Cat' hierarchicalLevel=3 setSize=2 posInSet=2 checkedState=1
+++++++++++staticText name='Cat'
+++++++++++++inlineTextBox name='Cat'
+++++++treeItem name='Wild' hierarchicalLevel=2 setSize=2 posInSet=2
+++++++++staticText name='Wild'
+++++++++++inlineTextBox name='Wild'
+++++treeItem name='Plants' hierarchicalLevel=1 setSize=2 posInSet=2
+++++++staticText name='Plants'
+++++++++inlineTextBox name='Plants'
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-tree-expected-mac.txt b/content/test/data/accessibility/aria/aria-tree-expected-mac.txt
index c01dad4..3374323 100644
--- a/content/test/data/accessibility/aria/aria-tree-expected-mac.txt
+++ b/content/test/data/accessibility/aria/aria-tree-expected-mac.txt
@@ -1,12 +1,12 @@
 AXWebArea
 ++AXOutline
-++++AXRow AXTitle='Animals ' AXARIASetSize='2' AXARIAPosInSet='1'
+++++AXRow AXTitle='Animals ' AXValue='2' AXARIASetSize='2' AXARIAPosInSet='1'
 ++++++AXStaticText AXValue='Animals'
 ++++++AXRow AXTitle='Domesticated ' AXARIASetSize='2' AXARIAPosInSet='1'
 ++++++++AXStaticText AXValue='Domesticated'
-++++++++AXRow AXTitle='Dog' AXARIASetSize='2' AXARIAPosInSet='1'
+++++++++AXRow AXTitle='Dog' AXValue='1' AXARIASetSize='2' AXARIAPosInSet='1'
 ++++++++++AXStaticText AXValue='Dog'
-++++++++AXRow AXTitle='Cat' AXARIASetSize='2' AXARIAPosInSet='2'
+++++++++AXRow AXTitle='Cat' AXValue='0' AXARIASetSize='2' AXARIAPosInSet='2'
 ++++++++++AXStaticText AXValue='Cat'
 ++++++AXRow AXTitle='Wild' AXARIASetSize='2' AXARIAPosInSet='2'
 ++++++++AXStaticText AXValue='Wild'
diff --git a/content/test/data/accessibility/aria/aria-tree-expected-win.txt b/content/test/data/accessibility/aria/aria-tree-expected-win.txt
index 2e8dd62..c8fa0fa 100644
--- a/content/test/data/accessibility/aria/aria-tree-expected-win.txt
+++ b/content/test/data/accessibility/aria/aria-tree-expected-win.txt
@@ -1,14 +1,14 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
-++ROLE_SYSTEM_OUTLINE
-++++ROLE_SYSTEM_OUTLINEITEM name='Animals ' level:1 setsize:2 posinset:1
+++ROLE_SYSTEM_OUTLINE IA2_STATE_VERTICAL
+++++ROLE_SYSTEM_OUTLINEITEM name='Animals ' MIXED IA2_STATE_CHECKABLE level:1 setsize:2 posinset:1 checkable:true
 ++++++ROLE_SYSTEM_STATICTEXT name='Animals'
 ++++++ROLE_SYSTEM_OUTLINEITEM name='Domesticated ' level:2 setsize:2 posinset:1
 ++++++++ROLE_SYSTEM_STATICTEXT name='Domesticated'
-++++++++ROLE_SYSTEM_OUTLINEITEM name='Dog' level:3 setsize:2 posinset:1
+++++++++ROLE_SYSTEM_OUTLINEITEM name='Dog' CHECKED IA2_STATE_CHECKABLE level:3 setsize:2 posinset:1 checkable:true
 ++++++++++ROLE_SYSTEM_STATICTEXT name='Dog'
-++++++++ROLE_SYSTEM_OUTLINEITEM name='Cat' level:3 setsize:2 posinset:2
+++++++++ROLE_SYSTEM_OUTLINEITEM name='Cat' IA2_STATE_CHECKABLE level:3 setsize:2 posinset:2 checkable:true
 ++++++++++ROLE_SYSTEM_STATICTEXT name='Cat'
 ++++++ROLE_SYSTEM_OUTLINEITEM name='Wild' level:2 setsize:2 posinset:2
 ++++++++ROLE_SYSTEM_STATICTEXT name='Wild'
 ++++ROLE_SYSTEM_OUTLINEITEM name='Plants' level:1 setsize:2 posinset:2
-++++++ROLE_SYSTEM_STATICTEXT name='Plants'
\ No newline at end of file
+++++++ROLE_SYSTEM_STATICTEXT name='Plants'
diff --git a/content/test/data/accessibility/aria/aria-tree.html b/content/test/data/accessibility/aria/aria-tree.html
index 7f798e83..0e964c8 100644
--- a/content/test/data/accessibility/aria/aria-tree.html
+++ b/content/test/data/accessibility/aria/aria-tree.html
@@ -3,15 +3,23 @@
 @WIN-ALLOW:setsize*
 @WIN-ALLOW:posinset*
 @WIN-ALLOW:level*
+@WIN-ALLOW:checkable:*
+@WIN-ALLOW:CHECKED*
+@WIN-ALLOW:IA2_STATE_*
+@WIN-ALLOW:MIXED*
+@BLINK-ALLOW:check*
+@BLINK-ALLOW:hierarchicalLevel*
+@BLINK-ALLOW:setSize*
+@BLINK-ALLOW:posInSet* 
 -->
 <!DOCTYPE html>
 <ul role="tree">
-  <li role="treeitem"><a href="#animals">Animals</a>
+  <li role="treeitem" aria-checked="mixed"><a href="#animals">Animals</a>
     <ul role="group">
       <li role="treeitem"><a href="#domesticated">Domesticated</a>
         <ul role="group">
-          <li role="treeitem"><a href="#dog">Dog</a></li>
-          <li role="treeitem"><a href="#cat">Cat</a></li>
+          <li role="treeitem" aria-checked="true"><a href="#dog">Dog</a></li>
+          <li role="treeitem" aria-checked="false"><a href="#cat">Cat</a></li>
         </ul>
       </li>
       <li role="treeitem"><a href="#wild">Wild</a></li>
diff --git a/content/test/data/accessibility/event/checked-state-changed-expected-mac.txt b/content/test/data/accessibility/event/checked-state-changed-expected-mac.txt
index f9d1daf..1a133cbd 100644
--- a/content/test/data/accessibility/event/checked-state-changed-expected-mac.txt
+++ b/content/test/data/accessibility/event/checked-state-changed-expected-mac.txt
@@ -1 +1,2 @@
 AXValueChanged on AXCheckBox AXDescription="My Checkbox"
+AXValueChanged on AXRow AXTitle="Treeitem"
diff --git a/content/test/data/accessibility/event/checked-state-changed-expected-win.txt b/content/test/data/accessibility/event/checked-state-changed-expected-win.txt
index b8beb68c..f25081ce 100644
--- a/content/test/data/accessibility/event/checked-state-changed-expected-win.txt
+++ b/content/test/data/accessibility/event/checked-state-changed-expected-win.txt
@@ -1 +1,2 @@
 EVENT_OBJECT_STATECHANGE on role=ROLE_SYSTEM_CHECKBUTTON name="My Checkbox" CHECKED,FOCUSABLE IA2_STATE_CHECKABLE
+EVENT_OBJECT_STATECHANGE on role=ROLE_SYSTEM_OUTLINEITEM name="Treeitem" CHECKED IA2_STATE_CHECKABLE
diff --git a/content/test/data/accessibility/event/checked-state-changed.html b/content/test/data/accessibility/event/checked-state-changed.html
index f891913..0178c3c 100644
--- a/content/test/data/accessibility/event/checked-state-changed.html
+++ b/content/test/data/accessibility/event/checked-state-changed.html
@@ -2,9 +2,11 @@
 <html>
 <body>
 <input id="c" type="checkbox" aria-label="My Checkbox">
+<div id="treeitem" role="treeitem" aria-checked="false">Treeitem</div>
 <script>
   function go() {
     document.getElementById('c').checked = true;
+    document.getElementById('treeitem').setAttribute('aria-checked', 'true');
   }
 </script>
 </body>
diff --git a/content/test/data/accessibility/event/pressed-state-change.html b/content/test/data/accessibility/event/pressed-state-change.html
new file mode 100644
index 0000000..02b77b4
--- /dev/null
+++ b/content/test/data/accessibility/event/pressed-state-change.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<body>
+<input id="c" type="button" aria-pressed="false" aria-label="My Button">
+<script>
+  function go() {
+    document.getElementById('c').setAttribute('aria-pressed', 'true');
+  }
+</script>
+</body>
+</html>
diff --git a/content/test/data/accessibility/event/pressed-state-changed-expected-mac.txt b/content/test/data/accessibility/event/pressed-state-changed-expected-mac.txt
new file mode 100644
index 0000000..034ebb1
--- /dev/null
+++ b/content/test/data/accessibility/event/pressed-state-changed-expected-mac.txt
@@ -0,0 +1 @@
+AXValueChanged on AXCheckBox AXDescription="My Button"
diff --git a/content/test/data/accessibility/event/pressed-state-changed-expected-win.txt b/content/test/data/accessibility/event/pressed-state-changed-expected-win.txt
new file mode 100644
index 0000000..e5eea2d
--- /dev/null
+++ b/content/test/data/accessibility/event/pressed-state-changed-expected-win.txt
@@ -0,0 +1 @@
+EVENT_OBJECT_STATECHANGE on role=ROLE_SYSTEM_PUSHBUTTON name="My Button" PRESSED,FOCUSABLE IA2_STATE_CHECKABLE
diff --git a/device/bluetooth/dbus/bluetooth_le_advertisement_service_provider.cc b/device/bluetooth/dbus/bluetooth_le_advertisement_service_provider.cc
index 3cb67fc..51494bb 100644
--- a/device/bluetooth/dbus/bluetooth_le_advertisement_service_provider.cc
+++ b/device/bluetooth/dbus/bluetooth_le_advertisement_service_provider.cc
@@ -301,7 +301,7 @@
     dict_entry_writer.AppendString(
         bluetooth_advertisement::kManufacturerDataProperty);
     dbus::MessageWriter variant_writer(NULL);
-    dict_entry_writer.OpenVariant("a{qay}", &variant_writer);
+    dict_entry_writer.OpenVariant("a{qv}", &variant_writer);
     AppendManufacturerDataVariant(&variant_writer);
     dict_entry_writer.CloseContainer(&variant_writer);
     array_writer->CloseContainer(&dict_entry_writer);
@@ -326,7 +326,7 @@
     dict_entry_writer.AppendString(
         bluetooth_advertisement::kServiceDataProperty);
     dbus::MessageWriter variant_writer(NULL);
-    dict_entry_writer.OpenVariant("a{say}", &variant_writer);
+    dict_entry_writer.OpenVariant("a{sv}", &variant_writer);
     AppendServiceDataVariant(&variant_writer);
     dict_entry_writer.CloseContainer(&variant_writer);
     array_writer->CloseContainer(&dict_entry_writer);
@@ -335,14 +335,17 @@
   void AppendManufacturerDataVariant(dbus::MessageWriter* writer) {
     DCHECK(manufacturer_data_);
     dbus::MessageWriter array_writer(NULL);
-    writer->OpenArray("{qay}", &array_writer);
+    writer->OpenArray("{qv}", &array_writer);
     for (const auto& m : *manufacturer_data_) {
       dbus::MessageWriter entry_writer(NULL);
 
       array_writer.OpenDictEntry(&entry_writer);
 
-      entry_writer.AppendUint32(m.first);
-      entry_writer.AppendArrayOfBytes(m.second.data(), m.second.size());
+      entry_writer.AppendUint16(m.first);
+      dbus::MessageWriter variant_writer(NULL);
+      entry_writer.OpenVariant("ay", &variant_writer);
+      variant_writer.AppendArrayOfBytes(m.second.data(), m.second.size());
+      entry_writer.CloseContainer(&variant_writer);
 
       array_writer.CloseContainer(&entry_writer);
     }
@@ -352,14 +355,17 @@
   void AppendServiceDataVariant(dbus::MessageWriter* writer) {
     DCHECK(service_data_);
     dbus::MessageWriter array_writer(NULL);
-    writer->OpenArray("{say}", &array_writer);
+    writer->OpenArray("{sv}", &array_writer);
     for (const auto& m : *service_data_) {
       dbus::MessageWriter entry_writer(NULL);
 
       array_writer.OpenDictEntry(&entry_writer);
 
       entry_writer.AppendString(m.first);
-      entry_writer.AppendArrayOfBytes(m.second.data(), m.second.size());
+      dbus::MessageWriter variant_writer(NULL);
+      entry_writer.OpenVariant("ay", &variant_writer);
+      variant_writer.AppendArrayOfBytes(m.second.data(), m.second.size());
+      entry_writer.CloseContainer(&variant_writer);
 
       array_writer.CloseContainer(&entry_writer);
     }
diff --git a/extensions/shell/renderer/shell_content_renderer_client.cc b/extensions/shell/renderer/shell_content_renderer_client.cc
index 8f505bf..706befc 100644
--- a/extensions/shell/renderer/shell_content_renderer_client.cc
+++ b/extensions/shell/renderer/shell_content_renderer_client.cc
@@ -97,6 +97,7 @@
     blink::WebLocalFrame* frame,
     ui::PageTransition transition_type,
     const blink::WebURL& url,
+    std::vector<std::unique_ptr<content::URLLoaderThrottle>>* throttles,
     GURL* new_url) {
   // TODO(jamescook): Cause an error for bad extension scheme requests?
   return false;
diff --git a/extensions/shell/renderer/shell_content_renderer_client.h b/extensions/shell/renderer/shell_content_renderer_client.h
index 5aad8dbb..23482b3 100644
--- a/extensions/shell/renderer/shell_content_renderer_client.h
+++ b/extensions/shell/renderer/shell_content_renderer_client.h
@@ -39,10 +39,12 @@
   blink::WebPlugin* CreatePluginReplacement(
       content::RenderFrame* render_frame,
       const base::FilePath& plugin_path) override;
-  bool WillSendRequest(blink::WebLocalFrame* frame,
-                       ui::PageTransition transition_type,
-                       const blink::WebURL& url,
-                       GURL* new_url) override;
+  bool WillSendRequest(
+      blink::WebLocalFrame* frame,
+      ui::PageTransition transition_type,
+      const blink::WebURL& url,
+      std::vector<std::unique_ptr<content::URLLoaderThrottle>>* throttles,
+      GURL* new_url) override;
   bool IsExternalPepperPlugin(const std::string& module_name) override;
   bool ShouldGatherSiteIsolationStats() const override;
   content::BrowserPluginDelegate* CreateBrowserPluginDelegate(
diff --git a/google_apis/gaia/oauth2_token_service.cc b/google_apis/gaia/oauth2_token_service.cc
index 9979a51..0f038579 100644
--- a/google_apis/gaia/oauth2_token_service.cc
+++ b/google_apis/gaia/oauth2_token_service.cc
@@ -66,7 +66,7 @@
 }
 
 OAuth2TokenService::RequestImpl::~RequestImpl() {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 }
 
 std::string OAuth2TokenService::RequestImpl::GetAccountId() const {
@@ -81,7 +81,7 @@
     const GoogleServiceAuthError& error,
     const std::string& access_token,
     const base::Time& expiration_date) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (error.state() == GoogleServiceAuthError::NONE)
     consumer_->OnGetTokenSuccess(this, access_token, expiration_date);
   else
@@ -395,6 +395,7 @@
 }
 
 OAuth2TokenService::~OAuth2TokenService() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // Release all the pending fetchers.
   pending_fetchers_.clear();
 }
@@ -480,7 +481,7 @@
     const std::string& client_secret,
     const ScopeSet& scopes,
     Consumer* consumer) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460 is
   // fixed.
@@ -631,7 +632,7 @@
     const std::string& client_id,
     const ScopeSet& scopes,
     const std::string& access_token) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   RemoveCacheEntry(
       RequestParameters(client_id,
                         account_id,
@@ -641,7 +642,7 @@
 }
 
 void OAuth2TokenService::OnFetchComplete(Fetcher* fetcher) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // Update the auth error state so auth errors are appropriately communicated
   // to the user.
@@ -708,7 +709,7 @@
 
 const OAuth2TokenService::CacheEntry* OAuth2TokenService::GetCacheEntry(
     const RequestParameters& request_parameters) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   TokenCache::iterator token_iterator = token_cache_.find(request_parameters);
   if (token_iterator == token_cache_.end())
     return NULL;
@@ -722,7 +723,7 @@
 bool OAuth2TokenService::RemoveCacheEntry(
     const RequestParameters& request_parameters,
     const std::string& token_to_remove) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   TokenCache::iterator token_iterator = token_cache_.find(request_parameters);
   if (token_iterator != token_cache_.end() &&
       token_iterator->second.access_token == token_to_remove) {
@@ -746,7 +747,7 @@
     const OAuth2TokenService::ScopeSet& scopes,
     const std::string& access_token,
     const base::Time& expiration_date) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   CacheEntry& token = token_cache_[RequestParameters(client_id,
                                                      account_id,
@@ -756,7 +757,7 @@
 }
 
 void OAuth2TokenService::ClearCache() {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   for (TokenCache::iterator iter = token_cache_.begin();
        iter != token_cache_.end(); ++iter) {
     for (auto& observer : diagnostics_observer_list_)
@@ -767,7 +768,7 @@
 }
 
 void OAuth2TokenService::ClearCacheForAccount(const std::string& account_id) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   for (TokenCache::iterator iter = token_cache_.begin();
        iter != token_cache_.end();
        /* iter incremented in body */) {
@@ -811,7 +812,7 @@
 
 void OAuth2TokenService::set_max_authorization_token_fetch_retries_for_testing(
     int max_retries) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   max_fetch_retry_num_ = max_retries;
 }
 
diff --git a/google_apis/gaia/oauth2_token_service.h b/google_apis/gaia/oauth2_token_service.h
index e0b1cf4..213058aa 100644
--- a/google_apis/gaia/oauth2_token_service.h
+++ b/google_apis/gaia/oauth2_token_service.h
@@ -16,7 +16,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
-#include "base/threading/non_thread_safe.h"
+#include "base/sequence_checker.h"
 #include "base/time/time.h"
 #include "google_apis/gaia/google_service_auth_error.h"
 #include "google_apis/gaia/oauth2_access_token_consumer.h"
@@ -53,7 +53,7 @@
 //
 // The caller of StartRequest() owns the returned request and is responsible to
 // delete the request even once the callback has been invoked.
-class OAuth2TokenService : public base::NonThreadSafe {
+class OAuth2TokenService {
  public:
   // A set of scopes in OAuth2 authentication.
   typedef std::set<std::string> ScopeSet;
@@ -221,7 +221,6 @@
   // operated on the UI thread.
   // TODO(davidroche): move this out of header file.
   class RequestImpl : public base::SupportsWeakPtr<RequestImpl>,
-                      public base::NonThreadSafe,
                       public Request {
    public:
     // |consumer| is required to outlive this.
@@ -242,6 +241,8 @@
     // |consumer_| to call back when this request completes.
     const std::string account_id_;
     Consumer* const consumer_;
+
+    SEQUENCE_CHECKER(sequence_checker_);
   };
 
   // Implement it in delegates if they want to report errors to the user.
@@ -388,6 +389,8 @@
                            SameScopesRequestedForDifferentClients);
   FRIEND_TEST_ALL_PREFIXES(OAuth2TokenServiceTest, UpdateClearsCache);
 
+  SEQUENCE_CHECKER(sequence_checker_);
+
   DISALLOW_COPY_AND_ASSIGN(OAuth2TokenService);
 };
 
diff --git a/google_apis/gaia/oauth2_token_service_request.cc b/google_apis/gaia/oauth2_token_service_request.cc
index d88a20d..e3ce3ca 100644
--- a/google_apis/gaia/oauth2_token_service_request.cc
+++ b/google_apis/gaia/oauth2_token_service_request.cc
@@ -38,8 +38,7 @@
 //
 // 5. Core is destroyed on owner thread.
 class OAuth2TokenServiceRequest::Core
-    : public base::NonThreadSafe,
-      public base::RefCountedThreadSafe<OAuth2TokenServiceRequest::Core> {
+    : public base::RefCountedThreadSafe<OAuth2TokenServiceRequest::Core> {
  public:
   // Note the thread where an instance of Core is constructed is referred to as
   // the "owner thread" here.
@@ -72,6 +71,8 @@
   OAuth2TokenService* token_service();
   OAuth2TokenServiceRequest* owner();
 
+  SEQUENCE_CHECKER(sequence_checker_);
+
  private:
   friend class base::RefCountedThreadSafe<OAuth2TokenServiceRequest::Core>;
 
@@ -102,7 +103,7 @@
 }
 
 void OAuth2TokenServiceRequest::Core::Start() {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   token_service_task_runner_->PostTask(
       FROM_HERE,
       base::Bind(&OAuth2TokenServiceRequest::Core::StartOnTokenServiceThread,
@@ -110,7 +111,7 @@
 }
 
 void OAuth2TokenServiceRequest::Core::Stop() {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!IsStopped());
 
   // Detaches |owner_| from this instance so |owner_| will be called back only
@@ -129,7 +130,7 @@
 }
 
 bool OAuth2TokenServiceRequest::Core::IsStopped() const {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   return owner_ == NULL;
 }
 
@@ -144,12 +145,12 @@
 }
 
 OAuth2TokenServiceRequest* OAuth2TokenServiceRequest::Core::owner() {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   return owner_;
 }
 
 void OAuth2TokenServiceRequest::Core::DoNothing() {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 }
 
 namespace {
@@ -255,14 +256,14 @@
 
 void RequestCore::InformOwnerOnGetTokenSuccess(std::string access_token,
                                                base::Time expiration_time) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (!IsStopped()) {
     consumer_->OnGetTokenSuccess(owner(), access_token, expiration_time);
   }
 }
 
 void RequestCore::InformOwnerOnGetTokenFailure(GoogleServiceAuthError error) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (!IsStopped()) {
     consumer_->OnGetTokenFailure(owner(), error);
   }
@@ -355,6 +356,7 @@
 }
 
 OAuth2TokenServiceRequest::~OAuth2TokenServiceRequest() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   core_->Stop();
 }
 
diff --git a/google_apis/gaia/oauth2_token_service_request.h b/google_apis/gaia/oauth2_token_service_request.h
index 4f288472..1ce0325 100644
--- a/google_apis/gaia/oauth2_token_service_request.h
+++ b/google_apis/gaia/oauth2_token_service_request.h
@@ -11,16 +11,15 @@
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "base/sequence_checker.h"
 #include "base/single_thread_task_runner.h"
-#include "base/threading/non_thread_safe.h"
 #include "google_apis/gaia/oauth2_token_service.h"
 
 // OAuth2TokenServiceRequest represents an asynchronous request to an
 // OAuth2TokenService that may live in another thread.
 //
 // An OAuth2TokenServiceRequest can be created and started from any thread.
-class OAuth2TokenServiceRequest : public OAuth2TokenService::Request,
-                                  public base::NonThreadSafe {
+class OAuth2TokenServiceRequest : public OAuth2TokenService::Request {
  public:
   class Core;
 
@@ -101,6 +100,8 @@
   const std::string account_id_;
   scoped_refptr<Core> core_;
 
+  SEQUENCE_CHECKER(sequence_checker_);
+
   DISALLOW_COPY_AND_ASSIGN(OAuth2TokenServiceRequest);
 };
 
diff --git a/ios/chrome/browser/about_flags.mm b/ios/chrome/browser/about_flags.mm
index 86b8745..7df5c90 100644
--- a/ios/chrome/browser/about_flags.mm
+++ b/ios/chrome/browser/about_flags.mm
@@ -241,6 +241,11 @@
     command_line->AppendSwitch(switches::kDisableSigninPromo);
   }
 
+  // Populate command line flag for the request mobile site experiment from the
+  // configuration plist.
+  if ([defaults boolForKey:@"RequestMobileSiteDisabled"])
+    command_line->AppendSwitch(switches::kDisableRequestMobileSite);
+
   ios::GetChromeBrowserProvider()->AppendSwitchesFromExperimentalSettings(
       defaults, command_line);
 }
diff --git a/ios/chrome/browser/chrome_switches.cc b/ios/chrome/browser/chrome_switches.cc
index 7c2d158d..624df12 100644
--- a/ios/chrome/browser/chrome_switches.cc
+++ b/ios/chrome/browser/chrome_switches.cc
@@ -47,6 +47,9 @@
 // Disables Physical Web scanning for nearby URLs.
 const char kDisableIOSPhysicalWeb[] = "disable-ios-physical-web";
 
+// Disables Request Mobile Site.
+const char kDisableRequestMobileSite[] = "disable-request-mobile-site";
+
 // Disables the Suggestions UI
 const char kDisableSuggestionsUI[] = "disable-suggestions-ui";
 
diff --git a/ios/chrome/browser/chrome_switches.h b/ios/chrome/browser/chrome_switches.h
index a795c579..ae7b4fa 100644
--- a/ios/chrome/browser/chrome_switches.h
+++ b/ios/chrome/browser/chrome_switches.h
@@ -20,6 +20,7 @@
 extern const char kDisablePaymentRequest[];
 extern const char kDisableTabStripAutoScrollNewTabs[];
 extern const char kDisableIOSPhysicalWeb[];
+extern const char kDisableRequestMobileSite[];
 extern const char kDisableSuggestionsUI[];
 
 extern const char kEnableContextualSearch[];
diff --git a/ios/chrome/browser/experimental_flags.h b/ios/chrome/browser/experimental_flags.h
index 090152bd..2eaa9ade5 100644
--- a/ios/chrome/browser/experimental_flags.h
+++ b/ios/chrome/browser/experimental_flags.h
@@ -75,6 +75,9 @@
 // Whether reader mode is enabled.
 bool IsReaderModeEnabled();
 
+// Whether request mobile site is enabled.
+bool IsRequestMobileSiteEnabled();
+
 // Whether the Sign In Flow via SFSafariViewController is enabled.
 bool IsSafariVCSignInEnabled();
 
diff --git a/ios/chrome/browser/experimental_flags.mm b/ios/chrome/browser/experimental_flags.mm
index 67bc6f56..b6a6097 100644
--- a/ios/chrome/browser/experimental_flags.mm
+++ b/ios/chrome/browser/experimental_flags.mm
@@ -205,6 +205,11 @@
       switches::kEnableReaderModeToolbarIcon);
 }
 
+bool IsRequestMobileSiteEnabled() {
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  return !command_line->HasSwitch(switches::kDisableRequestMobileSite);
+}
+
 bool IsSafariVCSignInEnabled() {
   return ![[NSUserDefaults standardUserDefaults]
       boolForKey:kSafariVCSignInDisabled];
diff --git a/ios/chrome/browser/resources/Settings.bundle/Experimental.plist b/ios/chrome/browser/resources/Settings.bundle/Experimental.plist
index d898bea2..7f4c7dee 100644
--- a/ios/chrome/browser/resources/Settings.bundle/Experimental.plist
+++ b/ios/chrome/browser/resources/Settings.bundle/Experimental.plist
@@ -30,6 +30,22 @@
 			<key>Type</key>
 			<string>PSGroupSpecifier</string>
 			<key>Title</key>
+			<string>Request Mobile Site</string>
+		</dict>
+		<dict>
+			<key>Type</key>
+			<string>PSToggleSwitchSpecifier</string>
+			<key>Title</key>
+			<string>Disable Request Mobile Site</string>
+			<key>Key</key>
+			<string>RequestMobileSiteDisabled</string>
+			<key>Default</key>
+			<false/>
+		</dict>
+		<dict>
+			<key>Type</key>
+			<string>PSGroupSpecifier</string>
+			<key>Title</key>
 			<string>iPad Tab Strip</string>
 		</dict>
 		<dict>
diff --git a/ios/chrome/browser/tabs/tab_model.mm b/ios/chrome/browser/tabs/tab_model.mm
index 2fcb7308..217053e 100644
--- a/ios/chrome/browser/tabs/tab_model.mm
+++ b/ios/chrome/browser/tabs/tab_model.mm
@@ -597,9 +597,16 @@
     return referencedFiles;
   // Check the currently open tabs for external files.
   for (Tab* tab in self) {
-    if (UrlIsExternalFileReference(tab.url)) {
-      NSString* fileName = base::SysUTF8ToNSString(tab.url.ExtractFileName());
-      [referencedFiles addObject:fileName];
+    const GURL& lastCommittedURL = tab.lastCommittedURL;
+    if (UrlIsExternalFileReference(lastCommittedURL)) {
+      [referencedFiles addObject:base::SysUTF8ToNSString(
+                                     lastCommittedURL.ExtractFileName())];
+    }
+    web::NavigationItem* pendingItem =
+        tab.webState->GetNavigationManager()->GetPendingItem();
+    if (pendingItem && UrlIsExternalFileReference(pendingItem->GetURL())) {
+      [referencedFiles addObject:base::SysUTF8ToNSString(
+                                     pendingItem->GetURL().ExtractFileName())];
     }
   }
   // Do the same for the recently closed tabs.
@@ -752,7 +759,9 @@
   BOOL closedNTPTab = NO;
   if (oldCount == 1) {
     Tab* tab = [self tabAtIndex:0];
-    if (tab.url == GURL(kChromeUINewTabURL)) {
+    BOOL hasPendingLoad =
+        tab.webState->GetNavigationManager()->GetPendingItem() != nullptr;
+    if (!hasPendingLoad && tab.lastCommittedURL == GURL(kChromeUINewTabURL)) {
       [self closeTab:tab];
       closedNTPTab = YES;
       oldCount = 0;
diff --git a/ios/chrome/browser/tabs/tab_model_unittest.mm b/ios/chrome/browser/tabs/tab_model_unittest.mm
index 004cc4f..9857518 100644
--- a/ios/chrome/browser/tabs/tab_model_unittest.mm
+++ b/ios/chrome/browser/tabs/tab_model_unittest.mm
@@ -349,6 +349,8 @@
                               openedByDOM:NO
                                   atIndex:0
                              inBackground:NO];
+  web::WebStateImpl* web_state = static_cast<web::WebStateImpl*>(tab.webState);
+  web_state->GetNavigationManagerImpl().CommitPendingItem();
 
   SessionWindowIOS* window(CreateSessionWindow());
   [tab_model_ restoreSessionWindow:window];
@@ -368,6 +370,8 @@
                                openedByDOM:NO
                                    atIndex:0
                               inBackground:NO];
+  web::WebStateImpl* web_state = static_cast<web::WebStateImpl*>(tab0.webState);
+  web_state->GetNavigationManagerImpl().CommitPendingItem();
   Tab* tab1 = [tab_model_ insertTabWithURL:GURL(kChromeUINewTabURL)
                                   referrer:web::Referrer()
                                 transition:ui::PAGE_TRANSITION_TYPED
@@ -375,6 +379,8 @@
                                openedByDOM:NO
                                    atIndex:1
                               inBackground:NO];
+  web_state = static_cast<web::WebStateImpl*>(tab1.webState);
+  web_state->GetNavigationManagerImpl().CommitPendingItem();
 
   SessionWindowIOS* window(CreateSessionWindow());
   [tab_model_ restoreSessionWindow:window];
@@ -399,6 +405,8 @@
                               openedByDOM:NO
                                   atIndex:0
                              inBackground:NO];
+  web::WebStateImpl* web_state = static_cast<web::WebStateImpl*>(tab.webState);
+  web_state->GetNavigationManagerImpl().CommitPendingItem();
 
   SessionWindowIOS* window(CreateSessionWindow());
   [tab_model_ restoreSessionWindow:window];
diff --git a/ios/chrome/browser/ui/activity_services/share_to_data_builder.mm b/ios/chrome/browser/ui/activity_services/share_to_data_builder.mm
index 3fca2118..f35d996 100644
--- a/ios/chrome/browser/ui/activity_services/share_to_data_builder.mm
+++ b/ios/chrome/browser/ui/activity_services/share_to_data_builder.mm
@@ -31,7 +31,7 @@
   BOOL isPagePrintable = [tab viewForPrinting] != nil;
   ThumbnailGeneratorBlock thumbnailGenerator =
       activity_services::ThumbnailGeneratorForTab(tab);
-  return [[ShareToData alloc] initWithURL:tab.url
+  return [[ShareToData alloc] initWithURL:tab.visibleURL
                                     title:tab.title
                           isOriginalTitle:(tab.originalTitle != nil)
                           isPagePrintable:isPagePrintable
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm
index 9e4e1b4..6dfaffb 100644
--- a/ios/chrome/browser/ui/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -4063,7 +4063,7 @@
       [[_model currentTab] reloadWithUserAgentType:web::UserAgentType::DESKTOP];
       break;
     case IDC_REQUEST_MOBILE_SITE:
-      NOTREACHED();
+      [[_model currentTab] reloadWithUserAgentType:web::UserAgentType::MOBILE];
       break;
     case IDC_SHOW_TOOLS_MENU: {
       [self showToolsMenuPopup];
diff --git a/ios/chrome/browser/ui/payments/cells/BUILD.gn b/ios/chrome/browser/ui/payments/cells/BUILD.gn
index 4e0069c..f4f148bc 100644
--- a/ios/chrome/browser/ui/payments/cells/BUILD.gn
+++ b/ios/chrome/browser/ui/payments/cells/BUILD.gn
@@ -22,12 +22,14 @@
   ]
 
   deps = [
+    "//ios/chrome/app/theme",
     "//ios/chrome/browser/ui",
     "//ios/chrome/browser/ui/autofill:autofill_ui",
     "//ios/chrome/browser/ui/collection_view/cells",
     "//ios/chrome/browser/ui/colors",
     "//ios/third_party/material_components_ios",
     "//ios/third_party/material_roboto_font_loader_ios",
+    "//url/",
   ]
 
   configs += [ "//build/config/compiler:enable_arc" ]
diff --git a/ios/chrome/browser/ui/payments/cells/page_info_item.h b/ios/chrome/browser/ui/payments/cells/page_info_item.h
index 1275ef7..0eac31b 100644
--- a/ios/chrome/browser/ui/payments/cells/page_info_item.h
+++ b/ios/chrome/browser/ui/payments/cells/page_info_item.h
@@ -13,6 +13,9 @@
 // The accessibility identifier for the favicon image view.
 extern NSString* const kPageInfoFaviconImageViewID;
 
+// The accessibility identifier for the lock indicator image view.
+extern NSString* const kPageInfoLockIndicatorImageViewID;
+
 // PageInfoItem is the model class corresponding to PageInfoCell.
 @interface PageInfoItem : CollectionViewItem
 
@@ -25,22 +28,29 @@
 // The page host text to display.
 @property(nonatomic, copy) NSString* pageHost;
 
+// Whether or not the connection is secure.
+@property(nonatomic, assign, getter=isConnectionSecure) BOOL connectionSecure;
+
 @end
 
-// PageInfoCell implements a MDCCollectionViewCell subclass containing an image
-// view displaying the current page's favicon and two text labels representing
-// the current page's title and host. The image is laid out on the leading edge
-// of the cell while the two labels are laid out trailing the image and one on
-// top of the other, filling the full width of the cell.  Labels are truncated
-// as needed to fit in the cell.
+// PageInfoCell implements a MDCCollectionViewCell subclass containing two image
+// views displaying the current page's favicon and a lock indicator if
+// connection is secure and two text labels representing the current page's
+// title and host. The favicon image is laid out on the leading edge of the cell
+// while the two labels are laid out trailing the favicon and one on top of the
+// other, filling the full width of the cell, if the connection is not secure.
+// In the case that the connection is secure, the lock indicator image is placed
+// ahead of the host label and trails the favicon image. Labels are truncated as
+// needed to fit in the cell.
 @interface PageInfoCell : MDCCollectionViewCell
 
 // UILabels containing the page's title and host.
 @property(nonatomic, readonly, strong) UILabel* pageTitleLabel;
 @property(nonatomic, readonly, strong) UILabel* pageHostLabel;
 
-// UIImageView containing the page's favicon.
+// UIImageViews containing the page's favicon and lock indicator.
 @property(nonatomic, readonly, strong) UIImageView* pageFaviconView;
+@property(nonatomic, readonly, strong) UIImageView* pageLockIndicatorView;
 
 @end
 
diff --git a/ios/chrome/browser/ui/payments/cells/page_info_item.mm b/ios/chrome/browser/ui/payments/cells/page_info_item.mm
index 98db8d2..1364f12 100644
--- a/ios/chrome/browser/ui/payments/cells/page_info_item.mm
+++ b/ios/chrome/browser/ui/payments/cells/page_info_item.mm
@@ -4,14 +4,21 @@
 
 #import "ios/chrome/browser/ui/payments/cells/page_info_item.h"
 
+#import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
+#import "ios/chrome/browser/ui/uikit_ui_util.h"
+#include "ios/chrome/grit/ios_theme_resources.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
 #import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
+#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#include "url/url_constants.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
 NSString* const kPageInfoFaviconImageViewID = @"kPageInfoFaviconImageViewID";
+NSString* const kPageInfoLockIndicatorImageViewID =
+    @"kPageInfoLockIndicatorImageViewID";
 
 namespace {
 // Padding used on the top and bottom edges of the cell.
@@ -20,6 +27,21 @@
 // Padding used on the leading and trailing edges of the cell and between the
 // favicon and labels.
 const CGFloat kHorizontalPadding = 16;
+
+// Dimension for lock indicator in points.
+const CGFloat kLockIndicatorDimension = 16;
+
+// There is some empty space between the left and right edges of the lock
+// indicator image contents and the square box it is contained within.
+// This padding represents that difference. This is useful when it comes
+// to aligning the lock indicator image with the title label.
+const CGFloat kLockIndicatorHorizontalPadding = 4;
+
+// There is some empty space between the top and bottom edges of the lock
+// indicator image contents and the square box it is contained within.
+// This padding represents that difference. This is useful when it comes
+// to aligning the lock indicator image with the bottom of the host label.
+const CGFloat kLockIndicatorVerticalPadding = 4;
 }
 
 @implementation PageInfoItem
@@ -27,6 +49,7 @@
 @synthesize pageFavicon = _pageFavicon;
 @synthesize pageTitle = _pageTitle;
 @synthesize pageHost = _pageHost;
+@synthesize connectionSecure = _connectionSecure;
 
 #pragma mark CollectionViewItem
 
@@ -42,7 +65,27 @@
   [super configureCell:cell];
   cell.pageFaviconView.image = self.pageFavicon;
   cell.pageTitleLabel.text = self.pageTitle;
-  cell.pageHostLabel.text = self.pageHost;
+
+  if (self.connectionSecure) {
+    cell.pageHostLabel.text = [NSString
+        stringWithFormat:@"%s://%@", url::kHttpsScheme, self.pageHost];
+    NSMutableAttributedString* text = [[NSMutableAttributedString alloc]
+        initWithString:cell.pageHostLabel.text];
+    [text addAttribute:NSForegroundColorAttributeName
+                 value:[[MDCPalette cr_greenPalette] tint700]
+                 range:NSMakeRange(0, strlen(url::kHttpsScheme))];
+    [cell.pageHostLabel setAttributedText:text];
+    // Set lock image. UIImageRenderingModeAlwaysTemplate is used so that
+    // the color of the lock indicator image can be changed to green.
+    cell.pageLockIndicatorView.image = [ResizeImage(
+        NativeImage(IDR_IOS_OMNIBOX_HTTPS_VALID),
+        CGSizeMake(kLockIndicatorDimension, kLockIndicatorDimension),
+        ProjectionMode::kAspectFillNoClipping)
+        imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
+  } else {
+    cell.pageHostLabel.text = self.pageHost;
+    cell.pageLockIndicatorView.image = nil;
+  }
 
   // Invalidate the constraints so that layout can account for whether or not a
   // favicon is present.
@@ -53,11 +96,13 @@
 
 @implementation PageInfoCell {
   NSLayoutConstraint* _pageTitleLabelLeadingConstraint;
+  NSLayoutConstraint* _pageHostLabelLeadingConstraint;
 }
 
 @synthesize pageTitleLabel = _pageTitleLabel;
 @synthesize pageHostLabel = _pageHostLabel;
 @synthesize pageFaviconView = _pageFaviconView;
+@synthesize pageLockIndicatorView = _pageLockIndicatorView;
 
 - (instancetype)initWithFrame:(CGRect)frame {
   self = [super initWithFrame:frame];
@@ -90,6 +135,15 @@
     _pageHostLabel.translatesAutoresizingMaskIntoConstraints = NO;
     [self.contentView addSubview:_pageHostLabel];
 
+    // Lock indicator
+    _pageLockIndicatorView = [[UIImageView alloc] initWithFrame:CGRectZero];
+    _pageLockIndicatorView.translatesAutoresizingMaskIntoConstraints = NO;
+    _pageLockIndicatorView.accessibilityIdentifier =
+        kPageInfoLockIndicatorImageViewID;
+    [_pageLockIndicatorView
+        setTintColor:[[MDCPalette cr_greenPalette] tint700]];
+    [self.contentView addSubview:_pageLockIndicatorView];
+
     // Layout
     [NSLayoutConstraint activateConstraints:@[
       [_pageFaviconView.leadingAnchor
@@ -103,11 +157,15 @@
       [_pageFaviconView.widthAnchor
           constraintEqualToAnchor:_pageFaviconView.heightAnchor],
 
-      // The constraint on the leading achor of the title label is activated in
-      // updateConstraints rather than here so that it can depend on whether a
-      // favicon is present or not.
-      [_pageHostLabel.leadingAnchor
-          constraintEqualToAnchor:_pageTitleLabel.leadingAnchor],
+      // The constraint on the leading anchor of the lock indicator is
+      // activated in updateConstraints rather than here so that it can
+      // depend on whether a favicon is present or not.
+      [_pageLockIndicatorView.leadingAnchor
+          constraintEqualToAnchor:_pageTitleLabel.leadingAnchor
+                         constant:-kLockIndicatorHorizontalPadding],
+      [_pageLockIndicatorView.bottomAnchor
+          constraintEqualToAnchor:_pageHostLabel.firstBaselineAnchor
+                         constant:kLockIndicatorVerticalPadding],
 
       [_pageTitleLabel.trailingAnchor
           constraintLessThanOrEqualToAnchor:self.contentView.trailingAnchor
@@ -140,6 +198,13 @@
                      constant:kHorizontalPadding];
   _pageTitleLabelLeadingConstraint.active = YES;
 
+  _pageHostLabelLeadingConstraint.active = NO;
+  _pageHostLabelLeadingConstraint = [_pageHostLabel.leadingAnchor
+      constraintEqualToAnchor:_pageLockIndicatorView.image
+                                  ? _pageLockIndicatorView.trailingAnchor
+                                  : _pageTitleLabel.leadingAnchor];
+  _pageHostLabelLeadingConstraint.active = YES;
+
   [super updateConstraints];
 }
 
diff --git a/ios/chrome/browser/ui/payments/cells/page_info_item_unittest.mm b/ios/chrome/browser/ui/payments/cells/page_info_item_unittest.mm
index 1cfa93a..c4e4cd7 100644
--- a/ios/chrome/browser/ui/payments/cells/page_info_item_unittest.mm
+++ b/ios/chrome/browser/ui/payments/cells/page_info_item_unittest.mm
@@ -22,10 +22,12 @@
   UIImage* pageFavicon = ios_internal::CollectionViewTestImage();
   NSString* pageTitle = @"The Greatest Website Ever";
   NSString* pageHost = @"www.greatest.example.com";
+  NSString* pageHostSecure = @"https://www.greatest.example.com";
 
   item.pageFavicon = pageFavicon;
   item.pageTitle = pageTitle;
   item.pageHost = pageHost;
+  item.connectionSecure = false;
 
   id cell = [[[item cellClass] alloc] init];
   ASSERT_TRUE([cell isMemberOfClass:[PageInfoCell class]]);
@@ -34,11 +36,30 @@
   EXPECT_FALSE(pageInfoCell.pageTitleLabel.text);
   EXPECT_FALSE(pageInfoCell.pageHostLabel.text);
   EXPECT_FALSE(pageInfoCell.pageFaviconView.image);
+  EXPECT_FALSE(pageInfoCell.pageLockIndicatorView.image);
 
   [item configureCell:pageInfoCell];
   EXPECT_NSEQ(pageTitle, pageInfoCell.pageTitleLabel.text);
   EXPECT_NSEQ(pageHost, pageInfoCell.pageHostLabel.text);
   EXPECT_NSEQ(pageFavicon, pageInfoCell.pageFaviconView.image);
+  EXPECT_FALSE(pageInfoCell.pageLockIndicatorView.image);
+
+  item.connectionSecure = true;
+
+  id cell2 = [[[item cellClass] alloc] init];
+  ASSERT_TRUE([cell2 isMemberOfClass:[PageInfoCell class]]);
+
+  PageInfoCell* pageInfoCell2 = cell2;
+  EXPECT_FALSE(pageInfoCell2.pageTitleLabel.text);
+  EXPECT_FALSE(pageInfoCell2.pageHostLabel.text);
+  EXPECT_FALSE(pageInfoCell2.pageFaviconView.image);
+  EXPECT_FALSE(pageInfoCell2.pageLockIndicatorView.image);
+
+  [item configureCell:pageInfoCell2];
+  EXPECT_NSEQ(pageTitle, pageInfoCell2.pageTitleLabel.text);
+  EXPECT_NSEQ(pageHostSecure, pageInfoCell2.pageHostLabel.text);
+  EXPECT_NSEQ(pageFavicon, pageInfoCell2.pageFaviconView.image);
+  EXPECT_TRUE(pageInfoCell2.pageLockIndicatorView.image);
 }
 
 }  // namespace
diff --git a/ios/chrome/browser/ui/payments/payment_request_coordinator.h b/ios/chrome/browser/ui/payments/payment_request_coordinator.h
index 7118835..aba67a2 100644
--- a/ios/chrome/browser/ui/payments/payment_request_coordinator.h
+++ b/ios/chrome/browser/ui/payments/payment_request_coordinator.h
@@ -101,6 +101,9 @@
 // calling |start|.
 @property(nonatomic, copy) NSString* pageHost;
 
+// Whether or not the connection is secure.
+@property(nonatomic, assign, getter=isConnectionSecure) BOOL connectionSecure;
+
 // The delegate to be notified when the user confirms or cancels the request.
 @property(nonatomic, weak) id<PaymentRequestCoordinatorDelegate> delegate;
 
diff --git a/ios/chrome/browser/ui/payments/payment_request_coordinator.mm b/ios/chrome/browser/ui/payments/payment_request_coordinator.mm
index e8785f6..e55ff25 100644
--- a/ios/chrome/browser/ui/payments/payment_request_coordinator.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_coordinator.mm
@@ -49,6 +49,7 @@
 @synthesize pageFavicon = _pageFavicon;
 @synthesize pageTitle = _pageTitle;
 @synthesize pageHost = _pageHost;
+@synthesize connectionSecure = _connectionSecure;
 @synthesize delegate = _delegate;
 
 - (void)start {
@@ -60,6 +61,7 @@
   [_viewController setPageFavicon:_pageFavicon];
   [_viewController setPageTitle:_pageTitle];
   [_viewController setPageHost:_pageHost];
+  [_viewController setConnectionSecure:_connectionSecure];
   [_viewController setDelegate:self];
   [_viewController setDataSource:_mediator];
   [_viewController loadModel];
diff --git a/ios/chrome/browser/ui/payments/payment_request_manager.mm b/ios/chrome/browser/ui/payments/payment_request_manager.mm
index 906134c..9fc18f8 100644
--- a/ios/chrome/browser/ui/payments/payment_request_manager.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_manager.mm
@@ -433,6 +433,8 @@
   NSString* pageTitle = base::SysUTF16ToNSString([self webState]->GetTitle());
   NSString* pageHost =
       base::SysUTF8ToNSString([self webState]->GetLastCommittedURL().host());
+  // TODO(crbug.com/728639): Determine when connection is secure.
+  BOOL connectionSecure = false;
   autofill::AutofillManager* autofillManager =
       autofill::AutofillDriverIOS::FromWebState(_webState)->autofill_manager();
   _paymentRequestCoordinator = [[PaymentRequestCoordinator alloc]
@@ -443,6 +445,7 @@
   [_paymentRequestCoordinator setPageFavicon:pageFavicon];
   [_paymentRequestCoordinator setPageTitle:pageTitle];
   [_paymentRequestCoordinator setPageHost:pageHost];
+  [_paymentRequestCoordinator setConnectionSecure:connectionSecure];
   [_paymentRequestCoordinator setDelegate:self];
 
   [_paymentRequestCoordinator start];
diff --git a/ios/chrome/browser/ui/payments/payment_request_view_controller.h b/ios/chrome/browser/ui/payments/payment_request_view_controller.h
index dcfad982..dd35694 100644
--- a/ios/chrome/browser/ui/payments/payment_request_view_controller.h
+++ b/ios/chrome/browser/ui/payments/payment_request_view_controller.h
@@ -74,6 +74,9 @@
 // The host of the page invoking the Payment Request API.
 @property(nonatomic, copy) NSString* pageHost;
 
+// Whether or not the connection is secure.
+@property(nonatomic, assign, getter=isConnectionSecure) BOOL connectionSecure;
+
 // Whether or not the view is in a pending state.
 @property(nonatomic, assign, getter=isPending) BOOL pending;
 
diff --git a/ios/chrome/browser/ui/payments/payment_request_view_controller.mm b/ios/chrome/browser/ui/payments/payment_request_view_controller.mm
index 0844d86..6fc74422 100644
--- a/ios/chrome/browser/ui/payments/payment_request_view_controller.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_view_controller.mm
@@ -123,6 +123,7 @@
 @synthesize pageFavicon = _pageFavicon;
 @synthesize pageTitle = _pageTitle;
 @synthesize pageHost = _pageHost;
+@synthesize connectionSecure = _connectionSecure;
 @synthesize pending = _pending;
 @synthesize delegate = _delegate;
 @synthesize showPaymentDataSource = _showPaymentDataSource;
@@ -211,6 +212,7 @@
   pageInfo.pageFavicon = _pageFavicon;
   pageInfo.pageTitle = _pageTitle;
   pageInfo.pageHost = _pageHost;
+  pageInfo.connectionSecure = _connectionSecure;
   [model setHeader:pageInfo forSectionWithIdentifier:SectionIdentifierSummary];
 
   if (_pending) {
diff --git a/ios/chrome/browser/ui/tools_menu/BUILD.gn b/ios/chrome/browser/ui/tools_menu/BUILD.gn
index c96edc3..6aaa68f 100644
--- a/ios/chrome/browser/ui/tools_menu/BUILD.gn
+++ b/ios/chrome/browser/ui/tools_menu/BUILD.gn
@@ -56,6 +56,7 @@
   deps = [
     ":tools_menu",
     "//base",
+    "//ios/chrome/browser:browser",
     "//ios/chrome/browser/ui/commands:commands",
     "//ios/shared/chrome/browser/ui/tools_menu",
     "//ios/web:user_agent",
@@ -67,6 +68,7 @@
   configs += [ "//build/config/compiler:enable_arc" ]
   testonly = true
   sources = [
+    "request_desktop_mobile_site_egtest.mm",
     "tools_popup_menu_egtest.mm",
   ]
   deps = [
@@ -74,11 +76,13 @@
     "//base",
     "//components/strings",
     "//ios/chrome/app/strings",
+    "//ios/chrome/browser:browser",
     "//ios/chrome/browser/ui",
     "//ios/chrome/browser/ui:ui_internal",
     "//ios/chrome/browser/ui/toolbar",
     "//ios/chrome/test/earl_grey:test_support",
     "//ios/third_party/earl_grey",
+    "//ios/web:test_support",
     "//ios/web/public/test",
     "//ios/web/public/test/http_server",
     "//ui/base",
diff --git a/ios/chrome/browser/ui/tools_menu/request_desktop_mobile_site_egtest.mm b/ios/chrome/browser/ui/tools_menu/request_desktop_mobile_site_egtest.mm
new file mode 100644
index 0000000..d79e503
--- /dev/null
+++ b/ios/chrome/browser/ui/tools_menu/request_desktop_mobile_site_egtest.mm
@@ -0,0 +1,307 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <EarlGrey/EarlGrey.h>
+#import <XCTest/XCTest.h>
+
+#include "base/strings/sys_string_conversions.h"
+#include "components/strings/grit/components_strings.h"
+#include "ios/chrome/browser/experimental_flags.h"
+#import "ios/chrome/browser/ui/chrome_web_view_factory.h"
+#import "ios/chrome/browser/ui/toolbar/toolbar_controller.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"
+#import "ios/chrome/test/earl_grey/accessibility_util.h"
+#import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
+#import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h"
+#import "ios/chrome/test/earl_grey/chrome_matchers.h"
+#import "ios/chrome/test/earl_grey/chrome_test_case.h"
+#include "ios/web/public/test/http_server/data_response_provider.h"
+#import "ios/web/public/test/http_server/http_server.h"
+#include "ios/web/public/test/http_server/http_server_util.h"
+#include "ios/web/public/test/http_server_util.h"
+#include "ui/base/l10n/l10n_util.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+using chrome_test_util::WebViewContainingText;
+
+namespace {
+
+const char kUserAgentTestURL[] =
+    "http://ios/testing/data/http_server_files/user_agent_test_page.html";
+
+const char kMobileSiteLabel[] = "Mobile";
+
+const char kDesktopSiteLabel[] = "Desktop";
+
+// Matcher for the button to request desktop site.
+id<GREYMatcher> RequestDesktopButton() {
+  return grey_accessibilityID(kToolsMenuRequestDesktopId);
+}
+
+// Matcher for the button to request mobile site.
+id<GREYMatcher> RequestMobileButton() {
+  return grey_accessibilityID(kToolsMenuRequestMobileId);
+}
+
+// A ResponseProvider that provides user agent for httpServer request.
+class UserAgentResponseProvider : public web::DataResponseProvider {
+ public:
+  bool CanHandleRequest(const Request& request) override { return true; }
+
+  void GetResponseHeadersAndBody(
+      const Request& request,
+      scoped_refptr<net::HttpResponseHeaders>* headers,
+      std::string* response_body) override {
+    // Do not return anything if static plist file has been requested,
+    // as plain text is not a valid property list content.
+    if ([[base::SysUTF8ToNSString(request.url.spec()) pathExtension]
+            isEqualToString:@"plist"]) {
+      *headers =
+          web::ResponseProvider::GetResponseHeaders("", net::HTTP_NO_CONTENT);
+      return;
+    }
+
+    *headers = web::ResponseProvider::GetDefaultResponseHeaders();
+    std::string userAgent;
+    const std::string kDesktopUserAgent =
+        base::SysNSStringToUTF8(ChromeWebView::kDesktopUserAgent);
+    if (request.headers.GetHeader("User-Agent", &userAgent) &&
+        userAgent == kDesktopUserAgent) {
+      response_body->assign("Desktop");
+    } else {
+      response_body->assign("Mobile");
+    }
+  }
+};
+}  // namespace
+
+// Tests for the tools popup menu.
+@interface RequestDesktopMobileSiteTestCase : ChromeTestCase
+@end
+
+@implementation RequestDesktopMobileSiteTestCase
+
+// Tests that requesting desktop site of a page works and the user agent
+// propagates to the next navigations in the same tab.
+- (void)testRequestDesktopSitePropagatesToNextNavigations {
+  std::unique_ptr<web::DataResponseProvider> provider(
+      new UserAgentResponseProvider());
+  web::test::SetUpHttpServer(std::move(provider));
+
+  [ChromeEarlGrey loadURL:web::test::HttpServer::MakeUrl("http://1.com")];
+  // Verify initial reception of the mobile site.
+  [[EarlGrey selectElementWithMatcher:WebViewContainingText(kMobileSiteLabel)]
+      assertWithMatcher:grey_notNil()];
+
+  // Request and verify reception of the desktop site.
+  [ChromeEarlGreyUI openToolsMenu];
+  [[EarlGrey selectElementWithMatcher:RequestDesktopButton()]
+      performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:WebViewContainingText(kDesktopSiteLabel)]
+      assertWithMatcher:grey_notNil()];
+
+  // Verify that desktop user agent propagates.
+  [ChromeEarlGrey loadURL:web::test::HttpServer::MakeUrl("http://2.com")];
+  [[EarlGrey selectElementWithMatcher:WebViewContainingText(kDesktopSiteLabel)]
+      assertWithMatcher:grey_notNil()];
+}
+
+// Tests that requesting desktop site of a page works and desktop user agent
+// does not propagate to next the new tab.
+- (void)testRequestDesktopSiteDoesNotPropagateToNewTab {
+  std::unique_ptr<web::DataResponseProvider> provider(
+      new UserAgentResponseProvider());
+  web::test::SetUpHttpServer(std::move(provider));
+
+  [ChromeEarlGrey loadURL:web::test::HttpServer::MakeUrl("http://1.com")];
+  // Verify initial reception of the mobile site.
+  [[EarlGrey selectElementWithMatcher:WebViewContainingText(kMobileSiteLabel)]
+      assertWithMatcher:grey_notNil()];
+
+  // Request and verify reception of the desktop site.
+  [ChromeEarlGreyUI openToolsMenu];
+  [[EarlGrey selectElementWithMatcher:RequestDesktopButton()]
+      performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:WebViewContainingText(kDesktopSiteLabel)]
+      assertWithMatcher:grey_notNil()];
+
+  // Verify that desktop user agent does not propagate to new tab.
+  [ChromeEarlGreyUI openNewTab];
+  [ChromeEarlGrey loadURL:web::test::HttpServer::MakeUrl("http://2.com")];
+  [[EarlGrey selectElementWithMatcher:WebViewContainingText(kMobileSiteLabel)]
+      assertWithMatcher:grey_notNil()];
+}
+
+// Tests that requesting desktop site of a page works and going back re-opens
+// mobile version of the page.
+- (void)testRequestDesktopSiteGoBackToMobile {
+  std::unique_ptr<web::DataResponseProvider> provider(
+      new UserAgentResponseProvider());
+  web::test::SetUpHttpServer(std::move(provider));
+
+  [ChromeEarlGrey loadURL:web::test::HttpServer::MakeUrl("http://1.com")];
+  // Verify initial reception of the mobile site.
+  [[EarlGrey selectElementWithMatcher:WebViewContainingText(kMobileSiteLabel)]
+      assertWithMatcher:grey_notNil()];
+
+  // Request and verify reception of the desktop site.
+  [ChromeEarlGreyUI openToolsMenu];
+  [[EarlGrey selectElementWithMatcher:RequestDesktopButton()]
+      performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:WebViewContainingText(kDesktopSiteLabel)]
+      assertWithMatcher:grey_notNil()];
+
+  // Verify that going back returns to the mobile site.
+  [[EarlGrey selectElementWithMatcher:chrome_test_util::BackButton()]
+      performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:WebViewContainingText(kMobileSiteLabel)]
+      assertWithMatcher:grey_notNil()];
+}
+
+// Tests that requesting mobile site of a page works and the user agent
+// propagates to the next navigations in the same tab.
+- (void)testRequestMobileSitePropagatesToNextNavigations {
+  if (!experimental_flags::IsRequestMobileSiteEnabled()) {
+    EARL_GREY_TEST_SKIPPED(@"Only enabled Request Mobile Site.");
+  }
+
+  std::unique_ptr<web::DataResponseProvider> provider(
+      new UserAgentResponseProvider());
+  web::test::SetUpHttpServer(std::move(provider));
+
+  [ChromeEarlGrey loadURL:web::test::HttpServer::MakeUrl("http://1.com")];
+  // Verify initial reception of the mobile site.
+  [[EarlGrey selectElementWithMatcher:WebViewContainingText(kMobileSiteLabel)]
+      assertWithMatcher:grey_notNil()];
+
+  // Request and verify reception of the desktop site.
+  [ChromeEarlGreyUI openToolsMenu];
+  [[EarlGrey selectElementWithMatcher:RequestDesktopButton()]
+      performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:WebViewContainingText(kDesktopSiteLabel)]
+      assertWithMatcher:grey_notNil()];
+
+  // Request and verify reception of the mobile site.
+  [ChromeEarlGreyUI openToolsMenu];
+  [[EarlGrey selectElementWithMatcher:RequestMobileButton()]
+      performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:WebViewContainingText(kMobileSiteLabel)]
+      assertWithMatcher:grey_notNil()];
+
+  // Verify that mobile user agent propagates.
+  [ChromeEarlGrey loadURL:web::test::HttpServer::MakeUrl("http://2.com")];
+  [[EarlGrey selectElementWithMatcher:WebViewContainingText(kMobileSiteLabel)]
+      assertWithMatcher:grey_notNil()];
+}
+
+// Tests that requesting mobile site of a page works and going back re-opens
+// desktop version of the page.
+- (void)testRequestMobileSiteGoBackToDesktop {
+  if (!experimental_flags::IsRequestMobileSiteEnabled()) {
+    EARL_GREY_TEST_SKIPPED(@"Only enabled Request Mobile Site.");
+  }
+
+  std::unique_ptr<web::DataResponseProvider> provider(
+      new UserAgentResponseProvider());
+  web::test::SetUpHttpServer(std::move(provider));
+
+  [ChromeEarlGrey loadURL:web::test::HttpServer::MakeUrl("http://1.com")];
+  // Verify initial reception of the mobile site.
+  [[EarlGrey selectElementWithMatcher:WebViewContainingText(kMobileSiteLabel)]
+      assertWithMatcher:grey_notNil()];
+
+  // Request and verify reception of the desktop site.
+  [ChromeEarlGreyUI openToolsMenu];
+  [[EarlGrey selectElementWithMatcher:RequestDesktopButton()]
+      performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:WebViewContainingText(kDesktopSiteLabel)]
+      assertWithMatcher:grey_notNil()];
+
+  // Request and verify reception of the mobile site.
+  [ChromeEarlGreyUI openToolsMenu];
+  [[EarlGrey selectElementWithMatcher:RequestMobileButton()]
+      performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:WebViewContainingText(kMobileSiteLabel)]
+      assertWithMatcher:grey_notNil()];
+
+  // Verify that going back returns to the desktop site.
+  [[EarlGrey selectElementWithMatcher:chrome_test_util::BackButton()]
+      performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:WebViewContainingText(kDesktopSiteLabel)]
+      assertWithMatcher:grey_notNil()];
+}
+
+// Tests that requesting desktop site button is not enabled on new tab pages.
+- (void)testRequestDesktopSiteNotEnabledOnNewTabPage {
+  // Verify tapping on request desktop button is no-op.
+  [ChromeEarlGreyUI openToolsMenu];
+  [[[EarlGrey selectElementWithMatcher:RequestDesktopButton()]
+      assertWithMatcher:grey_notNil()] performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:RequestDesktopButton()]
+      assertWithMatcher:grey_notNil()];
+}
+
+// Tests that requesting desktop site button is not enabled on WebUI pages.
+- (void)testRequestDesktopSiteNotEnabledOnWebUIPage {
+  [ChromeEarlGrey loadURL:GURL("chrome://version")];
+
+  // Verify tapping on request desktop button is no-op.
+  [ChromeEarlGreyUI openToolsMenu];
+  [[[EarlGrey selectElementWithMatcher:RequestDesktopButton()]
+      assertWithMatcher:grey_notNil()] performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:RequestDesktopButton()]
+      assertWithMatcher:grey_notNil()];
+}
+
+// Tests that navigator.appVersion JavaScript API returns correct string for
+// desktop User Agent.
+- (void)testAppVersionJSAPIWithDesktopUserAgent {
+  web::test::SetUpFileBasedHttpServer();
+  [ChromeEarlGrey loadURL:web::test::HttpServer::MakeUrl(kUserAgentTestURL)];
+  // Verify initial reception of the mobile site.
+  [[EarlGrey selectElementWithMatcher:WebViewContainingText(kMobileSiteLabel)]
+      assertWithMatcher:grey_notNil()];
+
+  // Request and verify reception of the desktop site.
+  [ChromeEarlGreyUI openToolsMenu];
+  [[EarlGrey selectElementWithMatcher:RequestDesktopButton()]
+      performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:WebViewContainingText(kDesktopSiteLabel)]
+      assertWithMatcher:grey_notNil()];
+}
+
+// Tests that navigator.appVersion JavaScript API returns correct string for
+// mobile User Agent.
+- (void)testAppVersionJSAPIWithMobileUserAgent {
+  if (!experimental_flags::IsRequestMobileSiteEnabled()) {
+    EARL_GREY_TEST_SKIPPED(@"Only enabled Request Mobile Site.");
+  }
+
+  web::test::SetUpFileBasedHttpServer();
+  [ChromeEarlGrey loadURL:web::test::HttpServer::MakeUrl(kUserAgentTestURL)];
+  // Verify initial reception of the mobile site.
+  [[EarlGrey selectElementWithMatcher:WebViewContainingText(kMobileSiteLabel)]
+      assertWithMatcher:grey_notNil()];
+
+  // Request and verify reception of the desktop site.
+  [ChromeEarlGreyUI openToolsMenu];
+  [[EarlGrey selectElementWithMatcher:RequestDesktopButton()]
+      performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:WebViewContainingText(kDesktopSiteLabel)]
+      assertWithMatcher:grey_notNil()];
+
+  // Request and verify reception of the mobile site.
+  [ChromeEarlGreyUI openToolsMenu];
+  [[EarlGrey selectElementWithMatcher:RequestMobileButton()]
+      performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:WebViewContainingText(kMobileSiteLabel)]
+      assertWithMatcher:grey_notNil()];
+}
+
+@end
diff --git a/ios/chrome/browser/ui/tools_menu/tools_menu_model.h b/ios/chrome/browser/ui/tools_menu/tools_menu_model.h
index dcd196b..4e88cd8 100644
--- a/ios/chrome/browser/ui/tools_menu/tools_menu_model.h
+++ b/ios/chrome/browser/ui/tools_menu/tools_menu_model.h
@@ -10,7 +10,7 @@
 #import "ios/shared/chrome/browser/ui/tools_menu/tools_menu_configuration.h"
 
 // Total number of possible menu items.
-const int kToolsMenuNumberOfItems = 15;
+const int kToolsMenuNumberOfItems = 16;
 
 // Initialization table for all possible commands to initialize the
 // tools menu at run time. Data initialized into this structure is not mutable.
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 51a3f37..7fc0a436 100644
--- a/ios/chrome/browser/ui/tools_menu/tools_menu_model.mm
+++ b/ios/chrome/browser/ui/tools_menu/tools_menu_model.mm
@@ -60,6 +60,9 @@
   { IDS_IOS_TOOLS_MENU_REQUEST_DESKTOP_SITE, kToolsMenuRequestDesktopId,
     IDC_REQUEST_DESKTOP_SITE,             ToolbarTypeWebAll,
     0,                                    nil },
+  { IDS_IOS_TOOLS_MENU_REQUEST_MOBILE_SITE, kToolsMenuRequestMobileId,
+    IDC_REQUEST_MOBILE_SITE,              ToolbarTypeWebAll,
+    0,                                    nil },
   { IDS_IOS_TOOLS_MENU_READER_MODE,       kToolsMenuReaderMode,
     IDC_READER_MODE,                      ToolbarTypeWebAll,
     0,                                    nil },
@@ -95,15 +98,16 @@
       return ios::GetChromeBrowserProvider()
           ->GetUserFeedbackProvider()
           ->IsUserFeedbackEnabled();
-    // TODO(crbug.com/696676): Talk to UI/UX people to decide the correct
-    // behavior of "Requestion Desktop/Mobile Site" (e.g. Whether user agent
-    // flag should stick when going backward and which cell should be visible
-    // when navigating to native pages).
     case IDS_IOS_TOOLS_MENU_REQUEST_DESKTOP_SITE:
-      return true;
+      if (experimental_flags::IsRequestMobileSiteEnabled())
+        return (configuration.userAgentType != web::UserAgentType::DESKTOP);
+      else
+        return true;
     case IDS_IOS_TOOLS_MENU_REQUEST_MOBILE_SITE:
-      NOTREACHED();
-      return false;
+      if (experimental_flags::IsRequestMobileSiteEnabled())
+        return (configuration.userAgentType == web::UserAgentType::DESKTOP);
+      else
+        return false;
     default:
       return true;
   }
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 9d5d853..372c0d0 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
@@ -37,7 +37,6 @@
 #include "ios/web/public/user_agent.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/l10n/l10n_util_mac.h"
-
 using ios::material::TimingFunction;
 
 namespace {
@@ -277,7 +276,12 @@
       break;
     case web::UserAgentType::DESKTOP:
       [self setItemEnabled:YES withTag:IDC_REQUEST_MOBILE_SITE];
-      [self setItemEnabled:NO withTag:IDC_REQUEST_DESKTOP_SITE];
+      if (!experimental_flags::IsRequestMobileSiteEnabled()) {
+        // When Request Mobile Site is disabled, the enabled state of Request
+        // Desktop Site button needs to be set to NO because it is visible even
+        // though the current UserAgentType is DESKTOP.
+        [self setItemEnabled:NO withTag:IDC_REQUEST_DESKTOP_SITE];
+      }
       break;
   }
 
diff --git a/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller_unittest.mm b/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller_unittest.mm
index 28d68fc..a9a30d19 100644
--- a/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller_unittest.mm
@@ -5,6 +5,7 @@
 #import "ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.h"
 
 #import "base/mac/scoped_nsobject.h"
+#include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/ui/commands/ios_command_ids.h"
 #import "ios/chrome/browser/ui/tools_menu/tools_menu_view_item.h"
 #import "ios/shared/chrome/browser/ui/tools_menu/tools_menu_configuration.h"
@@ -69,19 +70,27 @@
   EXPECT_FALSE(mobile_item);
 }
 
-// Tests that "Request Desktop Site" is visible and not enabled, and
-// "Request Mobile Site" is invisible when the current page is a web page and
-// uses DESKTOP user agent.
+// Tests that when the current page is a web page and uses DESKTOP user
+// agent, if request mobile site experiment is turned on, "Request Desktop Site"
+// is invisible, and "Request Mobile Site" is visible and enabled; otherwise,
+// "Request Desktop Site" is visible and not enabled, and "Request Mobile Site"
+// is invisible.
 TEST_F(ToolsMenuViewControllerTest, TestUserAgentTypeDESKTOP) {
   [configuration_ setUserAgentType:web::UserAgentType::DESKTOP];
   [controller_ initializeMenuWithConfiguration:configuration_.get()];
 
   ToolsMenuViewItem* desktop_item =
       GetToolsMenuViewItemWithTag(IDC_REQUEST_DESKTOP_SITE);
-  ASSERT_TRUE(desktop_item);
-  EXPECT_FALSE(desktop_item.active);
-
   ToolsMenuViewItem* mobile_item =
       GetToolsMenuViewItemWithTag(IDC_REQUEST_MOBILE_SITE);
-  EXPECT_FALSE(mobile_item);
+
+  if (experimental_flags::IsRequestMobileSiteEnabled()) {
+    EXPECT_FALSE(desktop_item);
+    ASSERT_TRUE(mobile_item);
+    EXPECT_TRUE(mobile_item.active);
+  } else {
+    ASSERT_TRUE(desktop_item);
+    EXPECT_FALSE(desktop_item.active);
+    EXPECT_FALSE(mobile_item);
+  }
 }
diff --git a/ios/chrome/browser/ui/tools_menu/tools_popup_menu_egtest.mm b/ios/chrome/browser/ui/tools_menu/tools_popup_menu_egtest.mm
index 3520c56e..ba37230 100644
--- a/ios/chrome/browser/ui/tools_menu/tools_popup_menu_egtest.mm
+++ b/ios/chrome/browser/ui/tools_menu/tools_popup_menu_egtest.mm
@@ -5,9 +5,6 @@
 #import <EarlGrey/EarlGrey.h>
 #import <XCTest/XCTest.h>
 
-#include "base/strings/sys_string_conversions.h"
-#include "components/strings/grit/components_strings.h"
-#import "ios/chrome/browser/ui/chrome_web_view_factory.h"
 #import "ios/chrome/browser/ui/toolbar/toolbar_controller.h"
 #include "ios/chrome/browser/ui/tools_menu/tools_menu_constants.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
@@ -17,7 +14,6 @@
 #import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h"
 #import "ios/chrome/test/earl_grey/chrome_matchers.h"
 #import "ios/chrome/test/earl_grey/chrome_test_case.h"
-#include "ios/web/public/test/http_server/data_response_provider.h"
 #import "ios/web/public/test/http_server/http_server.h"
 #include "ios/web/public/test/http_server/http_server_util.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -28,90 +24,21 @@
 
 namespace {
 
-// A ResponseProvider that provides user agent for httpServer request.
-class UserAgentResponseProvider : public web::DataResponseProvider {
- public:
-  bool CanHandleRequest(const Request& request) override { return true; }
-
-  void GetResponseHeadersAndBody(
-      const Request& request,
-      scoped_refptr<net::HttpResponseHeaders>* headers,
-      std::string* response_body) override {
-    // Do not return anything if static plist file has been requested,
-    // as plain text is not a valid property list content.
-    if ([[base::SysUTF8ToNSString(request.url.spec()) pathExtension]
-            isEqualToString:@"plist"]) {
-      *headers =
-          web::ResponseProvider::GetResponseHeaders("", net::HTTP_NO_CONTENT);
-      return;
-    }
-
-    *headers = web::ResponseProvider::GetDefaultResponseHeaders();
-    std::string userAgent;
-    const std::string kDesktopUserAgent =
-        base::SysNSStringToUTF8(ChromeWebView::kDesktopUserAgent);
-    if (request.headers.GetHeader("User-Agent", &userAgent) &&
-        userAgent == kDesktopUserAgent) {
-      response_body->assign("Desktop");
-    } else {
-      response_body->assign("Mobile");
-    }
-  }
-};
+const char kPDFURL[] = "http://ios/testing/data/http_server_files/testpage.pdf";
 
 // Matcher for the button to find in page.
 id<GREYMatcher> FindInPageButton() {
   return chrome_test_util::ButtonWithAccessibilityLabel(
       l10n_util::GetNSStringWithFixup(IDS_IOS_TOOLS_MENU_FIND_IN_PAGE));
 }
-
-// Matcher for the button to request desktop version.
-id<GREYMatcher> RequestDesktopButton() {
-  return grey_accessibilityID(kToolsMenuRequestDesktopId);
-}
-
-const char kPDFURL[] = "http://ios/testing/data/http_server_files/testpage.pdf";
-
 }  // namespace
 
 // Tests for the tools popup menu.
 @interface ToolsPopupMenuTestCase : ChromeTestCase
-- (void)verifyMobileAndDesktopVersions:(const GURL&)url;
 @end
 
 @implementation ToolsPopupMenuTestCase
 
-// Verify that requesting desktop and mobile versions works.
-- (void)verifyMobileAndDesktopVersions:(const GURL&)url {
-  NSString* const kMobileSiteLabel = @"Mobile";
-  NSString* const kDesktopSiteLabel = @"Desktop";
-
-  [ChromeEarlGrey loadURL:url];
-
-  // Verify initial reception of the mobile site.
-  [[EarlGrey
-      selectElementWithMatcher:chrome_test_util::WebViewContainingText(
-                                   base::SysNSStringToUTF8(kMobileSiteLabel))]
-      assertWithMatcher:grey_notNil()];
-
-  // Request and verify reception of the desktop site.
-  [ChromeEarlGreyUI openToolsMenu];
-  [[EarlGrey selectElementWithMatcher:RequestDesktopButton()]
-      performAction:grey_tap()];
-  [[EarlGrey
-      selectElementWithMatcher:chrome_test_util::WebViewContainingText(
-                                   base::SysNSStringToUTF8(kDesktopSiteLabel))]
-      assertWithMatcher:grey_notNil()];
-
-  // Verify that going back returns to the mobile site.
-  [[EarlGrey selectElementWithMatcher:chrome_test_util::BackButton()]
-      performAction:grey_tap()];
-  [[EarlGrey
-      selectElementWithMatcher:chrome_test_util::WebViewContainingText(
-                                   base::SysNSStringToUTF8(kMobileSiteLabel))]
-      assertWithMatcher:grey_notNil()];
-}
-
 // Tests that the menu is closed when tapping the close button.
 - (void)testOpenAndCloseToolsMenu {
   [ChromeEarlGreyUI openToolsMenu];
@@ -145,28 +72,6 @@
                             UIAccessibilityTraitNotEnabled)];
 }
 
-// Test requesting desktop version of page works and going back re-opens mobile
-// version of page.
-- (void)testToolsMenuRequestDesktopNetwork {
-  std::unique_ptr<web::DataResponseProvider> provider(
-      new UserAgentResponseProvider());
-  web::test::SetUpHttpServer(std::move(provider));
-
-  const GURL networkLayerTestURL =
-      web::test::HttpServer::MakeUrl("http://network");
-  [self verifyMobileAndDesktopVersions:networkLayerTestURL];
-}
-
-// Test requesting the desktop version of a page works correctly for
-// script-based desktop/mobile differentation.
-- (void)testToolsMenuRequestDesktopScript {
-  web::test::SetUpFileBasedHttpServer();
-  const GURL scriptLayerTestURL = web::test::HttpServer::MakeUrl(
-      "http://ios/testing/data/http_server_files/"
-      "request_desktop_test_page.html");
-  [self verifyMobileAndDesktopVersions:scriptLayerTestURL];
-}
-
 // Open tools menu and verify elements are accessible.
 - (void)testAccessibilityOnToolsMenu {
   [ChromeEarlGreyUI openToolsMenu];
diff --git a/ios/testing/BUILD.gn b/ios/testing/BUILD.gn
index 4751fa050..e4b8ef8 100644
--- a/ios/testing/BUILD.gn
+++ b/ios/testing/BUILD.gn
@@ -80,12 +80,12 @@
     "data/http_server_files/multi_field_form.html",
     "data/http_server_files/pony.html",
     "data/http_server_files/redirect_refresh.html",
-    "data/http_server_files/request_desktop_test_page.html",
     "data/http_server_files/single_page_wide.pdf",
     "data/http_server_files/state_operations.html",
     "data/http_server_files/state_operations.js",
     "data/http_server_files/testpage.pdf",
     "data/http_server_files/two_pages.pdf",
+    "data/http_server_files/user_agent_test_page.html",
     "data/http_server_files/window_close.html",
     "data/http_server_files/window_location.html",
     "data/http_server_files/window_location.js",
diff --git a/ios/testing/data/http_server_files/request_desktop_test_page.html b/ios/testing/data/http_server_files/user_agent_test_page.html
similarity index 90%
rename from ios/testing/data/http_server_files/request_desktop_test_page.html
rename to ios/testing/data/http_server_files/user_agent_test_page.html
index 0feb62c..b193cbe 100644
--- a/ios/testing/data/http_server_files/request_desktop_test_page.html
+++ b/ios/testing/data/http_server_files/user_agent_test_page.html
@@ -7,7 +7,7 @@
 <html>
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
-<title>Test Request Desktop Script Layer</title>
+<title>Test Request Desktop/Mobile Script</title>
 </head>
 <body>
 <script type="text/javascript">
diff --git a/ios/web/navigation/navigation_manager_impl.h b/ios/web/navigation/navigation_manager_impl.h
index 0c536125..ffc8a15 100644
--- a/ios/web/navigation/navigation_manager_impl.h
+++ b/ios/web/navigation/navigation_manager_impl.h
@@ -105,6 +105,9 @@
                       NavigationInitiationType initiation_type,
                       UserAgentOverrideOption user_agent_override_option);
 
+  // Commits the pending item, if any.
+  void CommitPendingItem();
+
   // NavigationManager:
   BrowserState* GetBrowserState() const override;
   WebState* GetWebState() const override;
diff --git a/ios/web/navigation/navigation_manager_impl.mm b/ios/web/navigation/navigation_manager_impl.mm
index bb034a6..f7c69ed0 100644
--- a/ios/web/navigation/navigation_manager_impl.mm
+++ b/ios/web/navigation/navigation_manager_impl.mm
@@ -212,6 +212,10 @@
   }
 }
 
+void NavigationManagerImpl::CommitPendingItem() {
+  [session_controller_ commitPendingItem];
+}
+
 BrowserState* NavigationManagerImpl::GetBrowserState() const {
   return browser_state_;
 }
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index ccd31a0..08f22bf 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -2878,7 +2878,7 @@
   self.userInteractionRegistered = NO;
   _pageHasZoomed = NO;
 
-  [[self sessionController] commitPendingItem];
+  self.navigationManagerImpl->CommitPendingItem();
 }
 
 - (void)wasShown {
diff --git a/ios/web_view/internal/cwv_web_view.mm b/ios/web_view/internal/cwv_web_view.mm
index b443c20..d228055f 100644
--- a/ios/web_view/internal/cwv_web_view.mm
+++ b/ios/web_view/internal/cwv_web_view.mm
@@ -79,6 +79,7 @@
 @property(nonatomic, readwrite) double estimatedProgress;
 @property(nonatomic, readwrite) BOOL canGoBack;
 @property(nonatomic, readwrite) BOOL canGoForward;
+@property(nonatomic, readwrite, copy) NSString* title;
 
 // Updates the availability of the back/forward navigation properties exposed
 // through |canGoBack| and |canGoForward|.
@@ -95,6 +96,7 @@
 @synthesize configuration = _configuration;
 @synthesize estimatedProgress = _estimatedProgress;
 @synthesize navigationDelegate = _navigationDelegate;
+@synthesize title = _title;
 @synthesize translationController = _translationController;
 @synthesize UIDelegate = _UIDelegate;
 @synthesize scrollView = _scrollView;
@@ -145,10 +147,6 @@
   return net::NSURLWithGURL(_webState->GetLastCommittedURL());
 }
 
-- (NSString*)title {
-  return base::SysUTF16ToNSString(_webState->GetTitle());
-}
-
 - (void)goBack {
   if (_webState->GetNavigationManager())
     _webState->GetNavigationManager()->GoBack();
@@ -231,6 +229,10 @@
   self.estimatedProgress = progress;
 }
 
+- (void)webStateDidChangeTitle:(web::WebState*)webState {
+  self.title = base::SysUTF16ToNSString(_webState->GetTitle());
+}
+
 - (void)renderProcessGoneForWebState:(web::WebState*)webState {
   SEL selector = @selector(webViewWebContentProcessDidTerminate:);
   if ([_navigationDelegate respondsToSelector:selector]) {
diff --git a/ios/web_view/public/cwv_web_view.h b/ios/web_view/public/cwv_web_view.h
index 6fe7298..f98cc08 100644
--- a/ios/web_view/public/cwv_web_view.h
+++ b/ios/web_view/public/cwv_web_view.h
@@ -48,7 +48,7 @@
 // The URL of the current document.
 @property(nonatomic, readonly) NSURL* lastCommittedURL;
 
-// The current page title.
+// The current page title. KVO compliant.
 @property(nonatomic, readonly, copy) NSString* title;
 
 // Page loading progress from 0.0 to 1.0. KVO compliant.
diff --git a/ios/web_view/test/BUILD.gn b/ios/web_view/test/BUILD.gn
index b4dbe82..1b25eda 100644
--- a/ios/web_view/test/BUILD.gn
+++ b/ios/web_view/test/BUILD.gn
@@ -16,11 +16,11 @@
 test("ios_web_view_inttests") {
   testonly = true
   sources = [
-    "boolean_observer.h",
-    "boolean_observer.mm",
     "chrome_web_view_kvo_inttest.mm",
     "chrome_web_view_test.h",
     "chrome_web_view_test.mm",
+    "observer.h",
+    "observer.mm",
     "web_view_interaction_test_util.h",
     "web_view_interaction_test_util.mm",
   ]
diff --git a/ios/web_view/test/boolean_observer.h b/ios/web_view/test/boolean_observer.h
deleted file mode 100644
index 154fe51..0000000
--- a/ios/web_view/test/boolean_observer.h
+++ /dev/null
@@ -1,35 +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_WEB_VIEW_TEST_BOOLEAN_OBSERVER_H_
-#define IOS_WEB_VIEW_TEST_BOOLEAN_OBSERVER_H_
-
-#import <Foundation/Foundation.h>
-
-// Class to observe a boolean KVO compliant property. To use this object, first
-// create an instance of BooleanObserver and call |setObservedObject:keyPath:|.
-// After an expected change in the value of |keyPath|, ask for |lastValue| and
-// compare to the expected value.
-@interface BooleanObserver : NSObject
-
-// The last value of performing |keyPath| on |object| after being notified of a
-// KVO value change or null if a change has not been observed.
-@property(nonatomic, nullable, readonly) NSNumber* lastValue;
-
-// The |keyPath| of |object| being observed.
-@property(nonatomic, nullable, readonly) NSString* keyPath;
-
-// The current |object| being observed.
-@property(nonatomic, nullable, readonly, weak) NSObject* object;
-
-// Sets the |object| and |keyPath| to observe. Performing |keyPath| on |object|
-// must return a BOOL value and |keyPath| must be KVO compliant.
-// If |object| is null and |self.object| is nonnull, |self.object| will stop
-// being observed. If |object| is nonnull, |keyPath| must be nonnull.
-- (void)setObservedObject:(nullable NSObject*)object
-                  keyPath:(nullable NSString*)keyPath;
-
-@end
-
-#endif  // IOS_WEB_VIEW_TEST_BOOLEAN_OBSERVER_H_
diff --git a/ios/web_view/test/chrome_web_view_kvo_inttest.mm b/ios/web_view/test/chrome_web_view_kvo_inttest.mm
index 4425439e..cf9d4ef 100644
--- a/ios/web_view/test/chrome_web_view_kvo_inttest.mm
+++ b/ios/web_view/test/chrome_web_view_kvo_inttest.mm
@@ -6,8 +6,10 @@
 #import <Foundation/Foundation.h>
 
 #import "base/mac/scoped_nsobject.h"
-#import "ios/web_view/test/boolean_observer.h"
+#include "base/strings/stringprintf.h"
+#import "base/strings/sys_string_conversions.h"
 #import "ios/web_view/test/chrome_web_view_test.h"
+#import "ios/web_view/test/observer.h"
 #import "ios/web_view/test/web_view_interaction_test_util.h"
 #import "net/base/mac/url_conversions.h"
 #include "testing/gtest_mac.h"
@@ -37,10 +39,10 @@
 
 // Tests that CWVWebView correctly reports |canGoBack| and |canGoForward| state.
 TEST_F(ChromeWebViewKvoTest, CanGoBackForward) {
-  BooleanObserver* back_observer = [[BooleanObserver alloc] init];
+  Observer* back_observer = [[Observer alloc] init];
   [back_observer setObservedObject:web_view_ keyPath:@"canGoBack"];
 
-  BooleanObserver* forward_observer = [[BooleanObserver alloc] init];
+  Observer* forward_observer = [[Observer alloc] init];
   [forward_observer setObservedObject:web_view_ keyPath:@"canGoForward"];
 
   ASSERT_FALSE(back_observer.lastValue);
@@ -51,11 +53,11 @@
 
   std::string page_2_html =
       "<a id='link_2' href='" + page_3_url.spec() + "'>Link 2</a>";
-  GURL page_2_url = GetUrlForPageWithHTMLBody(page_2_html);
+  GURL page_2_url = GetUrlForPageWithHtmlBody(page_2_html);
 
   std::string page_1_html =
       "<a id='link_1' href='" + page_2_url.spec() + "'>Link 1</a>";
-  GURL page_1_url = GetUrlForPageWithHTMLBody(page_1_html);
+  GURL page_1_url = GetUrlForPageWithHtmlBody(page_1_html);
 
   LoadUrl(web_view_, net::NSURLWithGURL(page_1_url));
   // Loading initial URL should not affect back/forward navigation state.
@@ -93,4 +95,33 @@
   EXPECT_TRUE([forward_observer.lastValue boolValue]);
 }
 
+// Tests that CWVWebView correctly reports current |title|.
+TEST_F(ChromeWebViewKvoTest, Title) {
+  Observer* observer = [[Observer alloc] init];
+  [observer setObservedObject:web_view_ keyPath:@"title"];
+
+  NSString* page_2_title = @"Page 2";
+  GURL page_2_url =
+      GetUrlForPageWithTitle(base::SysNSStringToUTF8(page_2_title));
+
+  NSString* page_1_title = @"Page 1";
+  std::string page_1_html = base::StringPrintf(
+      "<a id='link_1' href='%s'>Link 1</a>", page_2_url.spec().c_str());
+  GURL page_1_url = GetUrlForPageWithTitleAndBody(
+      base::SysNSStringToUTF8(page_1_title), page_1_html);
+
+  LoadUrl(web_view_, net::NSURLWithGURL(page_1_url));
+  EXPECT_NSEQ(page_1_title, observer.lastValue);
+
+  // Navigate to page 2.
+  EXPECT_TRUE(test::TapChromeWebViewElementWithId(web_view_, @"link_1"));
+  WaitForPageLoadCompletion(web_view_);
+  EXPECT_NSEQ(page_2_title, observer.lastValue);
+
+  // Navigate back to page 1.
+  [web_view_ goBack];
+  WaitForPageLoadCompletion(web_view_);
+  EXPECT_NSEQ(page_1_title, observer.lastValue);
+}
+
 }  // namespace ios_web_view
diff --git a/ios/web_view/test/chrome_web_view_test.h b/ios/web_view/test/chrome_web_view_test.h
index 5605a64..389338a 100644
--- a/ios/web_view/test/chrome_web_view_test.h
+++ b/ios/web_view/test/chrome_web_view_test.h
@@ -23,9 +23,8 @@
 namespace ios_web_view {
 
 // A test fixture for testing CWVWebView. A test server is also created to
-// support loading content. The server supports the urls defined by
-// RegisterDefaultHandlers in net/test/embedded_test_server/default_handlers.h
-// as well as urls returned by the GetUrl* methods below.
+// support loading content. The server supports the urls returned by the GetUrl*
+// methods below.
 class ChromeWebViewTest : public PlatformTest {
  protected:
   ChromeWebViewTest();
@@ -35,7 +34,12 @@
   GURL GetUrlForPageWithTitle(const std::string& title);
 
   // Returns URL to an html page with |html| within page's body tags.
-  GURL GetUrlForPageWithHTMLBody(const std::string& html);
+  GURL GetUrlForPageWithHtmlBody(const std::string& html);
+
+  // Returns URL to an html page with title set to |title| and |body| within
+  // the page's body tags.
+  GURL GetUrlForPageWithTitleAndBody(const std::string& title,
+                                     const std::string& body);
 
   // Loads |URL| in |web_view| and waits until the load completes. Asserts if
   // loading does not complete.
@@ -47,9 +51,8 @@
   // PlatformTest methods.
   void SetUp() override;
 
-  // Embedded server for handling responses to urls as registered by
-  // net/test/embedded_test_server/default_handlers.h and the GetURLForPageWith*
-  // methods.
+  // Embedded server for handling requests sent to the URLs returned by the
+  // GetURL* methods.
   std::unique_ptr<net::test_server::EmbeddedTestServer> test_server_;
 };
 
diff --git a/ios/web_view/test/chrome_web_view_test.mm b/ios/web_view/test/chrome_web_view_test.mm
index 44942e5..d124099 100644
--- a/ios/web_view/test/chrome_web_view_test.mm
+++ b/ios/web_view/test/chrome_web_view_test.mm
@@ -9,8 +9,9 @@
 
 #include "base/base64.h"
 #import "base/memory/ptr_util.h"
+#include "base/strings/stringprintf.h"
 #import "ios/testing/wait_util.h"
-#include "net/test/embedded_test_server/default_handlers.h"
+#include "net/base/url_util.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/embedded_test_server/http_request.h"
 #include "net/test/embedded_test_server/http_response.h"
@@ -22,33 +23,71 @@
 
 namespace {
 
-// Test server path which echos the remainder of the url as html. The html
-// must be base64 encoded.
-const char kPageHtmlBodyPath[] = "/PageHtmlBody?";
+// Test server path which renders a basic html page.
+const char kPageHtmlPath[] = "/PageHtml?";
+// URL parameter for html body. Value must be base64 encoded.
+const char kPageHtmlBodyParamName[] = "body";
+// URL parameter for page title. Value must be base64 encoded.
+const char kPageHtmlTitleParamName[] = "title";
 
-// Generates an html response from a request to |kPageHtmlBodyPath|.
-std::unique_ptr<net::test_server::HttpResponse> EchoPageHTMLBodyInResponse(
-    const net::test_server::HttpRequest& request) {
-  DCHECK(base::StartsWith(request.relative_url, kPageHtmlBodyPath,
-                          base::CompareCase::INSENSITIVE_ASCII));
-
-  std::string body = request.relative_url.substr(strlen(kPageHtmlBodyPath));
-
-  std::string unescaped_body;
-  base::Base64Decode(body, &unescaped_body);
-  std::string html = "<html><body>" + unescaped_body + "</body></html>";
+// Generates an html response.
+std::unique_ptr<net::test_server::HttpResponse> CreatePageHTMLResponse(
+    const std::string& title,
+    const std::string& body) {
+  std::string html = base::StringPrintf(
+      "<html><head><title>%s</title></head><body>%s</body></html>",
+      title.c_str(), body.c_str());
 
   auto http_response = base::MakeUnique<net::test_server::BasicHttpResponse>();
   http_response->set_content(html);
   return std::move(http_response);
 }
 
+// Returns true if |string| starts with |prefix|. String comparison is case
+// insensitive.
+bool StartsWith(std::string string, std::string prefix) {
+  return base::StartsWith(string, prefix, base::CompareCase::SENSITIVE);
+}
+
+// Encodes the |string| for use as the value of a url parameter.
+std::string EncodeQueryParamValue(std::string string) {
+  std::string encoded_string;
+  base::Base64Encode(string, &encoded_string);
+  return encoded_string;
+}
+
+// Decodes the |encoded_string|. Undoes the encoding performed by
+// |EncodeQueryParamValue|.
+std::string DecodeQueryParamValue(std::string encoded_string) {
+  std::string decoded_string;
+  base::Base64Decode(encoded_string, &decoded_string);
+  return decoded_string;
+}
+
 // Maps test server requests to responses.
 std::unique_ptr<net::test_server::HttpResponse> TestRequestHandler(
     const net::test_server::HttpRequest& request) {
-  if (base::StartsWith(request.relative_url, kPageHtmlBodyPath,
-                       base::CompareCase::INSENSITIVE_ASCII)) {
-    return EchoPageHTMLBodyInResponse(request);
+  if (StartsWith(request.relative_url, kPageHtmlPath)) {
+    std::string title;
+    std::string body;
+
+    GURL request_url = request.GetURL();
+
+    std::string encoded_title;
+    bool title_found = net::GetValueForKeyInQuery(
+        request_url, kPageHtmlTitleParamName, &encoded_title);
+    if (title_found) {
+      title = DecodeQueryParamValue(encoded_title);
+    }
+
+    std::string encoded_body;
+    bool body_found = net::GetValueForKeyInQuery(
+        request_url, kPageHtmlBodyParamName, &encoded_body);
+    if (body_found) {
+      body = DecodeQueryParamValue(encoded_body);
+    }
+
+    return CreatePageHTMLResponse(title, body);
   }
   return nullptr;
 }
@@ -60,7 +99,6 @@
 ChromeWebViewTest::ChromeWebViewTest()
     : test_server_(base::MakeUnique<net::EmbeddedTestServer>(
           net::test_server::EmbeddedTestServer::TYPE_HTTP)) {
-  net::test_server::RegisterDefaultHandlers(test_server_.get());
   test_server_->RegisterRequestHandler(base::Bind(&TestRequestHandler));
 }
 
@@ -72,13 +110,25 @@
 }
 
 GURL ChromeWebViewTest::GetUrlForPageWithTitle(const std::string& title) {
-  return test_server_->GetURL("/echotitle/" + title);
+  return GetUrlForPageWithTitleAndBody(title, std::string());
 }
 
-GURL ChromeWebViewTest::GetUrlForPageWithHTMLBody(const std::string& html) {
-  std::string base64_html;
-  base::Base64Encode(html, &base64_html);
-  return test_server_->GetURL(kPageHtmlBodyPath + base64_html);
+GURL ChromeWebViewTest::GetUrlForPageWithHtmlBody(const std::string& html) {
+  return GetUrlForPageWithTitleAndBody(std::string(), html);
+}
+
+GURL ChromeWebViewTest::GetUrlForPageWithTitleAndBody(const std::string& title,
+                                                      const std::string& body) {
+  GURL url = test_server_->GetURL(kPageHtmlPath);
+
+  // Encode |title| and |body| in url query in order to build the server
+  // response later in TestRequestHandler.
+  std::string encoded_title = EncodeQueryParamValue(title);
+  url = net::AppendQueryParameter(url, kPageHtmlTitleParamName, encoded_title);
+  std::string encoded_body = EncodeQueryParamValue(body);
+  url = net::AppendQueryParameter(url, kPageHtmlBodyParamName, encoded_body);
+
+  return url;
 }
 
 void ChromeWebViewTest::LoadUrl(CWVWebView* web_view, NSURL* url) {
diff --git a/ios/web_view/test/observer.h b/ios/web_view/test/observer.h
new file mode 100644
index 0000000..e940daf
--- /dev/null
+++ b/ios/web_view/test/observer.h
@@ -0,0 +1,32 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_WEB_VIEW_TEST_OBSERVER_H_
+#define IOS_WEB_VIEW_TEST_OBSERVER_H_
+
+#import <Foundation/Foundation.h>
+
+// Observes a KVO compliant property. To use this Observer, create an instance
+// and call |setObservedObject:keyPath:|. Then test expected values against
+// |lastValue|.
+@interface Observer : NSObject
+
+// The last value of performing |keyPath| on |object| after being notified of a
+// KVO value change or null if a change has not been observed.
+@property(nonatomic, nullable, readonly) id lastValue;
+
+// The |keyPath| of |object| being observed.
+@property(nonatomic, nullable, readonly) NSString* keyPath;
+
+// The current |object| being observed.
+@property(nonatomic, nullable, readonly, weak) NSObject* object;
+
+// Sets the |object| and |keyPath| to observe. The |keyPath| property of
+// |object| must exist and be KVO compliant.
+- (void)setObservedObject:(nonnull NSObject*)object
+                  keyPath:(nonnull NSString*)keyPath;
+
+@end
+
+#endif  // IOS_WEB_VIEW_TEST_OBSERVER_H_
diff --git a/ios/web_view/test/boolean_observer.mm b/ios/web_view/test/observer.mm
similarity index 81%
rename from ios/web_view/test/boolean_observer.mm
rename to ios/web_view/test/observer.mm
index fc2b5f2..b8d1cd73 100644
--- a/ios/web_view/test/boolean_observer.mm
+++ b/ios/web_view/test/observer.mm
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "ios/web_view/test/boolean_observer.h"
+#import "ios/web_view/test/observer.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
-@implementation BooleanObserver
+@implementation Observer
 
 @synthesize keyPath = _keyPath;
 @synthesize lastValue = _lastValue;
@@ -20,12 +20,10 @@
   _lastValue = nil;
   _keyPath = [keyPath copy];
   _object = object;
-  if (keyPath) {
-    [_object addObserver:self
-              forKeyPath:_keyPath
-                 options:NSKeyValueObservingOptionNew
-                 context:nil];
-  }
+  [_object addObserver:self
+            forKeyPath:_keyPath
+               options:NSKeyValueObservingOptionNew
+               context:nil];
 }
 
 - (void)observeValueForKeyPath:(NSString*)keyPath
diff --git a/media/gpu/ipc/client/gpu_jpeg_decode_accelerator_host.cc b/media/gpu/ipc/client/gpu_jpeg_decode_accelerator_host.cc
index 70ab1306..87cfc123 100644
--- a/media/gpu/ipc/client/gpu_jpeg_decode_accelerator_host.cc
+++ b/media/gpu/ipc/client/gpu_jpeg_decode_accelerator_host.cc
@@ -24,8 +24,7 @@
 // Class to receive AcceleratedJpegDecoderHostMsg_DecodeAck IPC message on IO
 // thread. This does very similar what MessageFilter usually does. It is not
 // MessageFilter because GpuChannelHost doesn't support AddFilter.
-class GpuJpegDecodeAcceleratorHost::Receiver : public IPC::Listener,
-                                               public base::NonThreadSafe {
+class GpuJpegDecodeAcceleratorHost::Receiver : public IPC::Listener {
  public:
   Receiver(Client* client,
            const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
@@ -34,11 +33,11 @@
         weak_factory_for_io_(
             base::MakeUnique<base::WeakPtrFactory<Receiver>>(this)),
         weak_ptr_for_io_(weak_factory_for_io_->GetWeakPtr()) {
-    DCHECK(CalledOnValidThread());
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   }
 
   ~Receiver() override {
-    DCHECK(CalledOnValidThread());
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     // If |io_task_runner_| no longer accepts tasks, |weak_factory_for_io_|
     // will leak. This is acceptable, because that should only happen on
     // Browser shutdown.
@@ -96,6 +95,8 @@
   // GPU IO task runner.
   scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
 
+  SEQUENCE_CHECKER(sequence_checker_);
+
   // Weak pointers will be invalidated on IO thread.
   std::unique_ptr<base::WeakPtrFactory<Receiver>> weak_factory_for_io_;
   base::WeakPtr<Receiver> weak_ptr_for_io_;
@@ -115,7 +116,7 @@
 }
 
 GpuJpegDecodeAcceleratorHost::~GpuJpegDecodeAcceleratorHost() {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   Send(new AcceleratedJpegDecoderMsg_Destroy(decoder_route_id_));
 
   if (receiver_) {
@@ -140,7 +141,7 @@
 
 bool GpuJpegDecodeAcceleratorHost::Initialize(
     JpegDecodeAccelerator::Client* client) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   bool succeeded = false;
   // This cannot be on IO thread because the msg is synchronous.
@@ -159,7 +160,7 @@
 void GpuJpegDecodeAcceleratorHost::Decode(
     const BitstreamBuffer& bitstream_buffer,
     const scoped_refptr<VideoFrame>& video_frame) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   DCHECK(
       base::SharedMemory::IsHandleValid(video_frame->shared_memory_handle()));
@@ -202,7 +203,7 @@
 }
 
 void GpuJpegDecodeAcceleratorHost::Send(IPC::Message* message) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (!channel_->Send(message)) {
     DLOG(ERROR) << "Send(" << message->type() << ") failed";
diff --git a/media/gpu/ipc/client/gpu_jpeg_decode_accelerator_host.h b/media/gpu/ipc/client/gpu_jpeg_decode_accelerator_host.h
index 4293961..26105f4 100644
--- a/media/gpu/ipc/client/gpu_jpeg_decode_accelerator_host.h
+++ b/media/gpu/ipc/client/gpu_jpeg_decode_accelerator_host.h
@@ -11,7 +11,7 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "base/threading/non_thread_safe.h"
+#include "base/sequence_checker.h"
 #include "media/video/jpeg_decode_accelerator.h"
 
 namespace base {
@@ -31,8 +31,7 @@
 
 // This class is used to talk to JpegDecodeAccelerator in the GPU process
 // through IPC messages.
-class GpuJpegDecodeAcceleratorHost : public JpegDecodeAccelerator,
-                                     public base::NonThreadSafe {
+class GpuJpegDecodeAcceleratorHost : public JpegDecodeAccelerator {
  public:
   GpuJpegDecodeAcceleratorHost(
       scoped_refptr<gpu::GpuChannelHost> channel,
@@ -65,6 +64,8 @@
 
   std::unique_ptr<Receiver> receiver_;
 
+  SEQUENCE_CHECKER(sequence_checker_);
+
   DISALLOW_COPY_AND_ASSIGN(GpuJpegDecodeAcceleratorHost);
 };
 
diff --git a/media/gpu/ipc/client/gpu_video_decode_accelerator_host.cc b/media/gpu/ipc/client/gpu_video_decode_accelerator_host.cc
index a28a42c00..e0cc707e 100644
--- a/media/gpu/ipc/client/gpu_video_decode_accelerator_host.cc
+++ b/media/gpu/ipc/client/gpu_video_decode_accelerator_host.cc
@@ -32,7 +32,7 @@
 }
 
 GpuVideoDecodeAcceleratorHost::~GpuVideoDecodeAcceleratorHost() {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (channel_ && decoder_route_id_ != MSG_ROUTING_NONE)
     channel_->RemoveRoute(decoder_route_id_);
@@ -43,7 +43,7 @@
 }
 
 bool GpuVideoDecodeAcceleratorHost::OnMessageReceived(const IPC::Message& msg) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP(GpuVideoDecodeAcceleratorHost, msg)
     IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_InitializationComplete,
@@ -69,7 +69,7 @@
 }
 
 void GpuVideoDecodeAcceleratorHost::OnChannelError() {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (channel_) {
     if (decoder_route_id_ != MSG_ROUTING_NONE)
       channel_->RemoveRoute(decoder_route_id_);
@@ -81,7 +81,7 @@
 
 bool GpuVideoDecodeAcceleratorHost::Initialize(const Config& config,
                                                Client* client) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   client_ = client;
 
   base::AutoLock lock(impl_lock_);
@@ -107,7 +107,7 @@
 
 void GpuVideoDecodeAcceleratorHost::Decode(
     const BitstreamBuffer& bitstream_buffer) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (!channel_)
     return;
   BitstreamBuffer buffer_to_send = bitstream_buffer;
@@ -124,7 +124,7 @@
 
 void GpuVideoDecodeAcceleratorHost::AssignPictureBuffers(
     const std::vector<PictureBuffer>& buffers) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (!channel_)
     return;
   // Rearrange data for IPC command.
@@ -148,7 +148,7 @@
 
 void GpuVideoDecodeAcceleratorHost::ReusePictureBuffer(
     int32_t picture_buffer_id) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (!channel_)
     return;
   Send(new AcceleratedVideoDecoderMsg_ReusePictureBuffer(decoder_route_id_,
@@ -156,14 +156,14 @@
 }
 
 void GpuVideoDecodeAcceleratorHost::Flush() {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (!channel_)
     return;
   Send(new AcceleratedVideoDecoderMsg_Flush(decoder_route_id_));
 }
 
 void GpuVideoDecodeAcceleratorHost::Reset() {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (!channel_)
     return;
   Send(new AcceleratedVideoDecoderMsg_Reset(decoder_route_id_));
@@ -172,7 +172,7 @@
 void GpuVideoDecodeAcceleratorHost::SetSurface(
     int32_t surface_id,
     const base::Optional<base::UnguessableToken>& routing_token) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (!channel_)
     return;
   Send(new AcceleratedVideoDecoderMsg_SetSurface(decoder_route_id_, surface_id,
@@ -180,7 +180,7 @@
 }
 
 void GpuVideoDecodeAcceleratorHost::Destroy() {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (channel_)
     Send(new AcceleratedVideoDecoderMsg_Destroy(decoder_route_id_));
   client_ = nullptr;
@@ -198,7 +198,7 @@
 }
 
 void GpuVideoDecodeAcceleratorHost::PostNotifyError(Error error) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DVLOG(2) << "PostNotifyError(): error=" << error;
   media_task_runner_->PostTask(
       FROM_HERE, base::Bind(&GpuVideoDecodeAcceleratorHost::OnNotifyError,
@@ -206,7 +206,7 @@
 }
 
 void GpuVideoDecodeAcceleratorHost::Send(IPC::Message* message) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   uint32_t message_type = message->type();
   if (!channel_->Send(message)) {
     DLOG(ERROR) << "Send(" << message_type << ") failed";
@@ -215,14 +215,14 @@
 }
 
 void GpuVideoDecodeAcceleratorHost::OnInitializationComplete(bool success) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (client_)
     client_->NotifyInitializationComplete(success);
 }
 
 void GpuVideoDecodeAcceleratorHost::OnBitstreamBufferProcessed(
     int32_t bitstream_buffer_id) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (client_)
     client_->NotifyEndOfBitstreamBuffer(bitstream_buffer_id);
 }
@@ -233,7 +233,7 @@
     uint32_t textures_per_buffer,
     const gfx::Size& dimensions,
     uint32_t texture_target) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   picture_buffer_dimensions_ = dimensions;
 
   const int kMaxVideoPlanes = 4;
@@ -251,14 +251,14 @@
 
 void GpuVideoDecodeAcceleratorHost::OnDismissPictureBuffer(
     int32_t picture_buffer_id) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (client_)
     client_->DismissPictureBuffer(picture_buffer_id);
 }
 
 void GpuVideoDecodeAcceleratorHost::OnPictureReady(
     const AcceleratedVideoDecoderHostMsg_PictureReady_Params& params) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (!client_)
     return;
   Picture picture(params.picture_buffer_id, params.bitstream_buffer_id,
@@ -271,19 +271,19 @@
 }
 
 void GpuVideoDecodeAcceleratorHost::OnFlushDone() {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (client_)
     client_->NotifyFlushDone();
 }
 
 void GpuVideoDecodeAcceleratorHost::OnResetDone() {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (client_)
     client_->NotifyResetDone();
 }
 
 void GpuVideoDecodeAcceleratorHost::OnNotifyError(uint32_t error) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (!client_)
     return;
   weak_this_factory_.InvalidateWeakPtrs();
diff --git a/media/gpu/ipc/client/gpu_video_decode_accelerator_host.h b/media/gpu/ipc/client/gpu_video_decode_accelerator_host.h
index 02deb5e..c80f4629 100644
--- a/media/gpu/ipc/client/gpu_video_decode_accelerator_host.h
+++ b/media/gpu/ipc/client/gpu_video_decode_accelerator_host.h
@@ -11,8 +11,8 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
 #include "base/single_thread_task_runner.h"
-#include "base/threading/non_thread_safe.h"
 #include "gpu/ipc/client/command_buffer_proxy_impl.h"
 #include "ipc/ipc_listener.h"
 #include "media/video/video_decode_accelerator.h"
@@ -31,8 +31,7 @@
 class GpuVideoDecodeAcceleratorHost
     : public IPC::Listener,
       public VideoDecodeAccelerator,
-      public gpu::CommandBufferProxyImpl::DeletionObserver,
-      public base::NonThreadSafe {
+      public gpu::CommandBufferProxyImpl::DeletionObserver {
  public:
   // |this| is guaranteed not to outlive |impl|.  (See comments for |impl_|.)
   explicit GpuVideoDecodeAcceleratorHost(gpu::CommandBufferProxyImpl* impl);
@@ -106,6 +105,9 @@
 
   // WeakPtr for posting tasks to ourself.
   base::WeakPtr<GpuVideoDecodeAcceleratorHost> weak_this_;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+
   base::WeakPtrFactory<GpuVideoDecodeAcceleratorHost> weak_this_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(GpuVideoDecodeAcceleratorHost);
diff --git a/media/gpu/ipc/client/gpu_video_encode_accelerator_host.cc b/media/gpu/ipc/client/gpu_video_encode_accelerator_host.cc
index df9f142..3f18bc0 100644
--- a/media/gpu/ipc/client/gpu_video_encode_accelerator_host.cc
+++ b/media/gpu/ipc/client/gpu_video_encode_accelerator_host.cc
@@ -30,7 +30,7 @@
 }
 
 GpuVideoEncodeAcceleratorHost::~GpuVideoEncodeAcceleratorHost() {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (channel_ && encoder_route_id_ != MSG_ROUTING_NONE)
     channel_->RemoveRoute(encoder_route_id_);
 
@@ -60,7 +60,7 @@
 }
 
 void GpuVideoEncodeAcceleratorHost::OnChannelError() {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (channel_) {
     if (encoder_route_id_ != MSG_ROUTING_NONE)
       channel_->RemoveRoute(encoder_route_id_);
@@ -71,7 +71,7 @@
 
 VideoEncodeAccelerator::SupportedProfiles
 GpuVideoEncodeAcceleratorHost::GetSupportedProfiles() {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (!channel_)
     return VideoEncodeAccelerator::SupportedProfiles();
   return GpuVideoAcceleratorUtil::ConvertGpuToMediaEncodeProfiles(
@@ -84,7 +84,7 @@
     VideoCodecProfile output_profile,
     uint32_t initial_bitrate,
     Client* client) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   client_ = client;
 
   base::AutoLock lock(impl_lock_);
@@ -117,7 +117,7 @@
 void GpuVideoEncodeAcceleratorHost::Encode(
     const scoped_refptr<VideoFrame>& frame,
     bool force_keyframe) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK_EQ(PIXEL_FORMAT_I420, frame->format());
   DCHECK_EQ(VideoFrame::STORAGE_SHMEM, frame->storage_type());
   if (!channel_)
@@ -141,7 +141,7 @@
 
 void GpuVideoEncodeAcceleratorHost::UseOutputBitstreamBuffer(
     const BitstreamBuffer& buffer) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (!channel_)
     return;
 
@@ -162,7 +162,7 @@
 void GpuVideoEncodeAcceleratorHost::RequestEncodingParametersChange(
     uint32_t bitrate,
     uint32_t framerate) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (!channel_)
     return;
 
@@ -171,7 +171,7 @@
 }
 
 void GpuVideoEncodeAcceleratorHost::Destroy() {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (channel_)
     Send(new AcceleratedVideoEncoderMsg_Destroy(encoder_route_id_));
   client_ = nullptr;
@@ -222,7 +222,7 @@
     const tracked_objects::Location& location,
     Error error,
     const std::string& message) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DLOG(ERROR) << "Error from " << location.function_name() << "("
               << location.file_name() << ":" << location.line_number() << ") "
               << message << " (error = " << error << ")";
@@ -233,7 +233,7 @@
 }
 
 void GpuVideoEncodeAcceleratorHost::Send(IPC::Message* message) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   uint32_t message_type = message->type();
   if (!channel_->Send(message)) {
     PostNotifyError(FROM_HERE, kPlatformFailureError,
@@ -245,7 +245,7 @@
     uint32_t input_count,
     const gfx::Size& input_coded_size,
     uint32_t output_buffer_size) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DVLOG(2) << __func__ << " input_count=" << input_count
            << ", input_coded_size=" << input_coded_size.ToString()
            << ", output_buffer_size=" << output_buffer_size;
@@ -256,7 +256,7 @@
 }
 
 void GpuVideoEncodeAcceleratorHost::OnNotifyInputDone(int32_t frame_id) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DVLOG(3) << __func__ << " frame_id=" << frame_id;
   // Fun-fact: std::hash_map is not spec'd to be re-entrant; since freeing a
   // frame can trigger a further encode to be kicked off and thus an .insert()
@@ -280,7 +280,7 @@
     uint32_t payload_size,
     bool key_frame,
     base::TimeDelta timestamp) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DVLOG(3) << __func__ << " bitstream_buffer_id=" << bitstream_buffer_id
            << ", payload_size=" << payload_size << ", key_frame=" << key_frame;
   if (client_)
@@ -289,7 +289,7 @@
 }
 
 void GpuVideoEncodeAcceleratorHost::OnNotifyError(Error error) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DLOG(ERROR) << __func__ << " error=" << error;
   if (!client_)
     return;
diff --git a/media/gpu/ipc/client/gpu_video_encode_accelerator_host.h b/media/gpu/ipc/client/gpu_video_encode_accelerator_host.h
index acf95724..9e5d48a 100644
--- a/media/gpu/ipc/client/gpu_video_encode_accelerator_host.h
+++ b/media/gpu/ipc/client/gpu_video_encode_accelerator_host.h
@@ -13,8 +13,8 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
 #include "base/single_thread_task_runner.h"
-#include "base/threading/non_thread_safe.h"
 #include "gpu/config/gpu_info.h"
 #include "gpu/ipc/client/command_buffer_proxy_impl.h"
 #include "ipc/ipc_listener.h"
@@ -43,8 +43,7 @@
 class GpuVideoEncodeAcceleratorHost
     : public IPC::Listener,
       public VideoEncodeAccelerator,
-      public gpu::CommandBufferProxyImpl::DeletionObserver,
-      public base::NonThreadSafe {
+      public gpu::CommandBufferProxyImpl::DeletionObserver {
  public:
   // |this| is guaranteed not to outlive |impl|.  (See comments for |impl_|.)
   explicit GpuVideoEncodeAcceleratorHost(gpu::CommandBufferProxyImpl* impl);
@@ -126,6 +125,8 @@
   // constructed.
   scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_;
 
+  SEQUENCE_CHECKER(sequence_checker_);
+
   // WeakPtr factory for posting tasks back to itself.
   base::WeakPtrFactory<GpuVideoEncodeAcceleratorHost> weak_this_factory_;
 
diff --git a/media/gpu/ipc/service/gpu_jpeg_decode_accelerator.cc b/media/gpu/ipc/service/gpu_jpeg_decode_accelerator.cc
index c2f6090..360039385 100644
--- a/media/gpu/ipc/service/gpu_jpeg_decode_accelerator.cc
+++ b/media/gpu/ipc/service/gpu_jpeg_decode_accelerator.cc
@@ -380,7 +380,7 @@
       client_number_(0) {}
 
 GpuJpegDecodeAccelerator::~GpuJpegDecodeAccelerator() {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (filter_) {
     channel_->RemoveFilter(filter_.get());
   }
@@ -388,7 +388,7 @@
 
 void GpuJpegDecodeAccelerator::AddClient(int32_t route_id,
                                          base::Callback<void(bool)> response) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // When adding non-chromeos platforms, VideoCaptureGpuJpegDecoder::Initialize
   // needs to be updated.
@@ -435,12 +435,12 @@
     int32_t route_id,
     int32_t buffer_id,
     JpegDecodeAccelerator::Error error) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   Send(new AcceleratedJpegDecoderHostMsg_DecodeAck(route_id, buffer_id, error));
 }
 
 void GpuJpegDecodeAccelerator::ClientRemoved() {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK_GT(client_number_, 0);
   client_number_--;
   if (client_number_ == 0) {
@@ -450,7 +450,7 @@
 }
 
 bool GpuJpegDecodeAccelerator::Send(IPC::Message* message) {
-  DCHECK(CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   return channel_->Send(message);
 }
 
diff --git a/media/gpu/ipc/service/gpu_jpeg_decode_accelerator.h b/media/gpu/ipc/service/gpu_jpeg_decode_accelerator.h
index f4a3c7a..d2459be3 100644
--- a/media/gpu/ipc/service/gpu_jpeg_decode_accelerator.h
+++ b/media/gpu/ipc/service/gpu_jpeg_decode_accelerator.h
@@ -12,8 +12,8 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
 #include "base/synchronization/waitable_event.h"
-#include "base/threading/non_thread_safe.h"
 #include "ipc/ipc_listener.h"
 #include "ipc/ipc_sender.h"
 #include "media/video/jpeg_decode_accelerator.h"
@@ -43,7 +43,6 @@
 
 class GpuJpegDecodeAccelerator
     : public IPC::Sender,
-      public base::NonThreadSafe,
       public base::SupportsWeakPtr<GpuJpegDecodeAccelerator> {
  public:
   // |channel| must outlive this object.
@@ -94,6 +93,8 @@
   // Number of clients added to |filter_|.
   int client_number_;
 
+  SEQUENCE_CHECKER(sequence_checker_);
+
   DISALLOW_IMPLICIT_CONSTRUCTORS(GpuJpegDecodeAccelerator);
 };
 
diff --git a/media/gpu/vaapi_picture.cc b/media/gpu/vaapi_picture.cc
index 921a424..3d678ef3 100644
--- a/media/gpu/vaapi_picture.cc
+++ b/media/gpu/vaapi_picture.cc
@@ -31,7 +31,9 @@
       client_texture_id_(client_texture_id),
       picture_buffer_id_(picture_buffer_id) {}
 
-VaapiPicture::~VaapiPicture() {}
+VaapiPicture::~VaapiPicture() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
 
 // static
 linked_ptr<VaapiPicture> VaapiPicture::CreatePicture(
diff --git a/media/gpu/vaapi_picture.h b/media/gpu/vaapi_picture.h
index fa9fa6d..020b2b91 100644
--- a/media/gpu/vaapi_picture.h
+++ b/media/gpu/vaapi_picture.h
@@ -15,7 +15,7 @@
 #include "base/macros.h"
 #include "base/memory/linked_ptr.h"
 #include "base/memory/ref_counted.h"
-#include "base/threading/non_thread_safe.h"
+#include "base/sequence_checker.h"
 #include "media/gpu/gpu_video_decode_accelerator_helpers.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/gpu_memory_buffer.h"
@@ -26,7 +26,7 @@
 class VaapiWrapper;
 
 // Picture is native pixmap abstraction (X11/Ozone).
-class VaapiPicture : public base::NonThreadSafe {
+class VaapiPicture {
  public:
   // Create a VaapiPicture of |size| to be associated with |picture_buffer_id|.
   // If provided, bind it to |texture_id|, as well as to |client_texture_id|
@@ -87,6 +87,8 @@
  private:
   int32_t picture_buffer_id_;
 
+  SEQUENCE_CHECKER(sequence_checker_);
+
   DISALLOW_COPY_AND_ASSIGN(VaapiPicture);
 };
 
diff --git a/net/android/java/src/org/chromium/net/NetworkChangeNotifier.java b/net/android/java/src/org/chromium/net/NetworkChangeNotifier.java
index 924e3b8..2cbeb9e 100644
--- a/net/android/java/src/org/chromium/net/NetworkChangeNotifier.java
+++ b/net/android/java/src/org/chromium/net/NetworkChangeNotifier.java
@@ -5,7 +5,6 @@
 package org.chromium.net;
 
 import android.annotation.SuppressLint;
-import android.content.Context;
 
 import org.chromium.base.ObserverList;
 import org.chromium.base.VisibleForTesting;
@@ -50,11 +49,6 @@
         mConnectionTypeObservers = new ObserverList<ConnectionTypeObserver>();
     }
 
-    // TODO(wnwen): Remove after downstream no longer depends on this.
-    public static NetworkChangeNotifier init(Context context) {
-        return init();
-    }
-
     /**
      * Initializes the singleton once.
      */
diff --git a/net/android/javatests/src/org/chromium/net/NetworkChangeNotifierNoNativeTest.java b/net/android/javatests/src/org/chromium/net/NetworkChangeNotifierNoNativeTest.java
index 5391a6f..9ec284a 100644
--- a/net/android/javatests/src/org/chromium/net/NetworkChangeNotifierNoNativeTest.java
+++ b/net/android/javatests/src/org/chromium/net/NetworkChangeNotifierNoNativeTest.java
@@ -5,7 +5,6 @@
 package org.chromium.net;
 
 import android.os.Looper;
-import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.MediumTest;
 
 import org.junit.Test;
@@ -27,7 +26,7 @@
     @MediumTest
     public void testNoNativeDependence() {
         Looper.prepare();
-        NetworkChangeNotifier.init(InstrumentationRegistry.getInstrumentation().getTargetContext());
+        NetworkChangeNotifier.init();
         NetworkChangeNotifier.registerToReceiveNotificationsAlways();
     }
 }
\ No newline at end of file
diff --git a/remoting/ios/app/host_collection_view_cell.mm b/remoting/ios/app/host_collection_view_cell.mm
index 7cbab27..1b8c33d 100644
--- a/remoting/ios/app/host_collection_view_cell.mm
+++ b/remoting/ios/app/host_collection_view_cell.mm
@@ -10,8 +10,6 @@
 
 #import "remoting/ios/app/host_collection_view_cell.h"
 
-#import "ios/third_party/material_components_ios/src/components/ShadowElevations/src/MaterialShadowElevations.h"
-#import "ios/third_party/material_components_ios/src/components/ShadowLayer/src/MaterialShadowLayer.h"
 #import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #import "remoting/ios/domain/host_info.h"
 
@@ -24,7 +22,7 @@
   UIImageView* _imageView;
   UILabel* _statusLabel;
   UILabel* _titleLabel;
-  UIView* _cellView;
+  UIView* _labelView;
 }
 @end
 
@@ -37,10 +35,6 @@
 
 @synthesize hostInfo = _hostInfo;
 
-+ (Class)layerClass {
-  return [MDCShadowLayer class];
-}
-
 - (id)initWithFrame:(CGRect)frame {
   self = [super initWithFrame:frame];
   if (self) {
@@ -51,49 +45,81 @@
 }
 
 - (void)commonInit {
-  _cellView = [[UIView alloc] initWithFrame:self.bounds];
-  _cellView.autoresizingMask =
-      UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
-  _cellView.backgroundColor = [UIColor whiteColor];
-  _cellView.clipsToBounds = YES;
-  [self addSubview:_cellView];
-
-  MDCShadowLayer* shadowLayer = (MDCShadowLayer*)self.layer;
-  shadowLayer.shadowMaskEnabled = NO;
-  [shadowLayer setElevation:MDCShadowElevationCardResting];
-
-  CGRect imageViewFrame =
-      CGRectMake(kHostCardIconInset,
-                 self.frame.size.height / 2.f - kHostCardIconSize / 2.f,
-                 kHostCardIconSize, kHostCardIconSize);
-  _imageView = [[UIImageView alloc] initWithFrame:imageViewFrame];
+  _imageView = [[UIImageView alloc] init];
+  _imageView.translatesAutoresizingMaskIntoConstraints = NO;
   _imageView.contentMode = UIViewContentModeCenter;
   _imageView.alpha = 0.87f;
   _imageView.backgroundColor = UIColor.lightGrayColor;
   _imageView.layer.cornerRadius = kHostCardIconSize / 2.f;
   _imageView.layer.masksToBounds = YES;
-  [_cellView addSubview:_imageView];
+  [self.contentView addSubview:_imageView];
+
+  // Holds both of the labels.
+  _labelView = [[UIView alloc] init];
+  _labelView.translatesAutoresizingMaskIntoConstraints = NO;
+  [self.contentView addSubview:_labelView];
 
   _titleLabel = [[UILabel alloc] init];
+  _titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
   _titleLabel.font = [MDCTypography titleFont];
   _titleLabel.alpha = [MDCTypography titleFontOpacity];
   _titleLabel.textColor = [UIColor colorWithWhite:0 alpha:0.87f];
-  _titleLabel.frame = CGRectMake(
-      imageViewFrame.origin.x + imageViewFrame.size.width + kHostCardIconInset,
-      (self.frame.size.height / 2.f) -
-          (_titleLabel.font.pointSize + kHostCardPadding / 2.f),
-      self.frame.size.width, _titleLabel.font.pointSize + kLinePadding);
-  [_cellView addSubview:_titleLabel];
+  [_labelView addSubview:_titleLabel];
 
   _statusLabel = [[UILabel alloc] init];
+  _statusLabel.translatesAutoresizingMaskIntoConstraints = NO;
   _statusLabel.font = [MDCTypography captionFont];
   _statusLabel.alpha = [MDCTypography captionFontOpacity];
   _statusLabel.textColor = [UIColor colorWithWhite:0 alpha:0.60f];
-  _statusLabel.frame = CGRectMake(
-      imageViewFrame.origin.x + imageViewFrame.size.width + kHostCardIconInset,
-      (self.frame.size.height / 2.f) + kHostCardPadding / 2.f,
-      self.frame.size.width, _statusLabel.font.pointSize + kLinePadding);
-  [_cellView addSubview:_statusLabel];
+  [_labelView addSubview:_statusLabel];
+
+  // Constraints
+  NSArray* constraints = @[
+    // +------------+---------------+
+    // | +--------+ |               |
+    // | |        | | [Host Name]   |
+    // | |  Icon  | | - - - - - - - | <- Center Y
+    // | |        | | [Host Status] |
+    // | +---^----+ |               |
+    // +-----|------+-------^-------+
+    //       |              |
+    //  Image View     Label View
+    [[_imageView leadingAnchor]
+        constraintEqualToAnchor:[self.contentView leadingAnchor]
+                       constant:kHostCardIconInset],
+    [[_imageView centerYAnchor]
+        constraintEqualToAnchor:[self.contentView centerYAnchor]],
+    [[_imageView widthAnchor] constraintEqualToConstant:kHostCardIconSize],
+    [[_imageView heightAnchor] constraintEqualToConstant:kHostCardIconSize],
+
+    [[_labelView leadingAnchor]
+        constraintEqualToAnchor:[_imageView trailingAnchor]
+                       constant:kHostCardIconInset],
+    [[_labelView trailingAnchor]
+        constraintEqualToAnchor:[self.contentView trailingAnchor]
+                       constant:-kHostCardPadding / 2.f],
+    [[_labelView topAnchor]
+        constraintEqualToAnchor:[self.contentView topAnchor]],
+    [[_labelView bottomAnchor]
+        constraintEqualToAnchor:[self.contentView bottomAnchor]],
+
+    // Put titleLable and statusLable symmetrically around centerY.
+    [[_titleLabel leadingAnchor]
+        constraintEqualToAnchor:[_labelView leadingAnchor]],
+    [[_titleLabel trailingAnchor]
+        constraintEqualToAnchor:[_labelView trailingAnchor]],
+    [[_titleLabel bottomAnchor]
+        constraintEqualToAnchor:[_labelView centerYAnchor]],
+
+    [[_statusLabel leadingAnchor]
+        constraintEqualToAnchor:[_labelView leadingAnchor]],
+    [[_statusLabel trailingAnchor]
+        constraintEqualToAnchor:[_labelView trailingAnchor]],
+    [[_statusLabel topAnchor] constraintEqualToAnchor:[_labelView centerYAnchor]
+                                             constant:kLinePadding],
+  ];
+
+  [NSLayoutConstraint activateConstraints:constraints];
 }
 
 #pragma mark - HostCollectionViewCell Public
diff --git a/remoting/ios/app/host_collection_view_controller.mm b/remoting/ios/app/host_collection_view_controller.mm
index 4724cb4..3d415c8 100644
--- a/remoting/ios/app/host_collection_view_controller.mm
+++ b/remoting/ios/app/host_collection_view_controller.mm
@@ -49,9 +49,7 @@
 - (void)viewDidLoad {
   [super viewDidLoad];
   self.styler.cellStyle = MDCCollectionViewCellStyleCard;
-  self.styler.cellLayoutType = MDCCollectionViewCellLayoutTypeGrid;
-  self.styler.gridPadding = 0;
-  self.styler.gridColumnCount = 1;
+  self.styler.cellLayoutType = MDCCollectionViewCellLayoutTypeList;
 }
 
 - (void)viewWillTransitionToSize:(CGSize)size
diff --git a/remoting/ios/app/remoting_view_controller.mm b/remoting/ios/app/remoting_view_controller.mm
index 215fd4b3..1f28e5e 100644
--- a/remoting/ios/app/remoting_view_controller.mm
+++ b/remoting/ios/app/remoting_view_controller.mm
@@ -50,7 +50,7 @@
 - (instancetype)init {
   _isAuthenticated = NO;
   UICollectionViewFlowLayout* layout =
-      [[UICollectionViewFlowLayout alloc] init];
+      [[MDCCollectionViewFlowLayout alloc] init];
   layout.minimumInteritemSpacing = 0;
   CGFloat sectionInset = kHostInset * 2.f;
   [layout setSectionInset:UIEdgeInsetsMake(sectionInset, sectionInset,
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h
index f8f7bba..89224b7f 100644
--- a/skia/config/SkUserConfig.h
+++ b/skia/config/SkUserConfig.h
@@ -216,10 +216,6 @@
 #define SK_SUPPORT_LEGACY_GRADIENT_ALPHATRUNC
 #endif
 
-#ifndef SK_SUPPORT_LEGACY_RASTERPIPELINE
-#define SK_SUPPORT_LEGACY_RASTERPIPELINE
-#endif
-
 ///////////////////////// Imported from BUILD.gn and skia_common.gypi
 
 /* In some places Skia can use static initializers for global initialization,
diff --git a/storage/browser/blob/shareable_file_reference.cc b/storage/browser/blob/shareable_file_reference.cc
index 0f0e0b97..27a224ac2 100644
--- a/storage/browser/blob/shareable_file_reference.cc
+++ b/storage/browser/blob/shareable_file_reference.cc
@@ -9,15 +9,15 @@
 
 #include "base/lazy_instance.h"
 #include "base/macros.h"
+#include "base/sequence_checker.h"
 #include "base/task_runner.h"
-#include "base/threading/non_thread_safe.h"
 
 namespace storage {
 
 namespace {
 
-// A shareable file map with enforcement of thread checker.
-class ShareableFileMap : public base::NonThreadSafe {
+// A shareable file map with enforcement of sequence checker.
+class ShareableFileMap {
  public:
   typedef std::map<base::FilePath, ShareableFileReference*> FileMap;
   typedef FileMap::iterator iterator;
@@ -26,32 +26,39 @@
 
   ShareableFileMap() {}
 
-  ~ShareableFileMap() {
-    DetachFromThread();
-  }
+  ~ShareableFileMap() = default;
 
   iterator Find(key_type key) {
-    DCHECK(CalledOnValidThread());
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     return file_map_.find(key);
   }
 
   iterator End() {
-    DCHECK(CalledOnValidThread());
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     return file_map_.end();
   }
 
   std::pair<iterator, bool> Insert(value_type value) {
-    DCHECK(CalledOnValidThread());
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     return file_map_.insert(value);
   }
 
   void Erase(key_type key) {
-    DCHECK(CalledOnValidThread());
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     file_map_.erase(key);
   }
 
+#if DCHECK_IS_ON()
+  void AssertCalledOnValidSequence() const {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  }
+#endif  // DCHECK_IS_ON()
+
  private:
   FileMap file_map_;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+
   DISALLOW_COPY_AND_ASSIGN(ShareableFileMap);
 };
 
@@ -102,7 +109,9 @@
 
 void ShareableFileReference::AddFinalReleaseCallback(
     const FinalReleaseCallback& callback) {
-  DCHECK(g_file_map.Get().CalledOnValidThread());
+#if DCHECK_IS_ON()
+  g_file_map.Get().AssertCalledOnValidSequence();
+#endif  // DCHECK_IS_ON()
   scoped_file_.AddScopeOutCallback(callback, NULL);
 }
 
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 04889da..5b20261 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -1466,24 +1466,6 @@
             ]
         }
     ],
-    "MetricsServiceUrl": [
-        {
-            "platforms": [
-                "chromeos",
-                "mac",
-                "win",
-                "linux"
-            ],
-            "experiments": [
-                {
-                    "name": "NewURL",
-                    "enable_features": [
-                        "NewMetricsUrl"
-                    ]
-                }
-            ]
-        }
-    ],
     "MidiManagerAndroid": [
         {
             "platforms": [
diff --git a/third_party/WebKit/LayoutTests/NeverFixTests b/third_party/WebKit/LayoutTests/NeverFixTests
index c3d008a..0e56f9c 100644
--- a/third_party/WebKit/LayoutTests/NeverFixTests
+++ b/third_party/WebKit/LayoutTests/NeverFixTests
@@ -752,6 +752,7 @@
 external/wpt/css/css-writing-modes-3/page-flow-direction-srl-004.xht [ WontFix ]
 external/wpt/2dcontext/drawing-paths-to-the-canvas/canvas_focus_drawFocusIfNeeded_AAPI_001-manual.html [ WontFix ]
 external/wpt/html/semantics/embedded-content/the-img-element/ismap/img-ismap-coordinates-manual.html [ WontFix ]
+external/wpt/css/css-flexbox-1/css-flexbox-height-animation-stretch.html [ WontFix ]
 
 # These directories have manual tests that don't have to run with
 # run-webkit-tests; see https://crbug.com/359838.
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 78b70c5a..9045e0d 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1331,9 +1331,6 @@
 crbug.com/492664 external/wpt/css/css-writing-modes-3/table-progression-vrl-003.html [ Failure ]
 crbug.com/492664 external/wpt/css/css-writing-modes-3/table-progression-vrl-004.html [ Failure ]
 
-# An animated manual test that should not be run
-crbug.com/728522 external/wpt/css/css-flexbox-1/css-flexbox-height-animation-stretch.html [ Skip ]
-
 crbug.com/637055 fast/css/outline-offset-large.html [ Skip ]
 
 # Either "combo" or split should run: http://testthewebforward.org/docs/css-naming.html
@@ -1660,6 +1657,10 @@
 crbug.com/310004 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-basic-textarea-vert-001.xhtml [ Failure ]
 crbug.com/310004 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-basic-video-vert-001.xhtml [ Failure ]
 
+# Skia change to spriteblitters
+crbug.com/728566 css3/blending/background-blend-mode-crossfade-image-gradient.html [ NeedsManualRebaseline ]
+crbug.com/728566 images/cross-fade-background-size.html [ NeedsManualRebaseline ]
+
 # We don't support requesting flex line breaks and it is not clear that we should.
 # See https://lists.w3.org/Archives/Public/www-style/2015May/0065.html
 crbug.com/473481 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-break-request-horiz-001a.html [ Failure ]
@@ -2969,6 +2970,9 @@
 crbug.com/724392 [ Win ] fast/css/font-family-case-insensitive.html [ Failure Pass Timeout ]
 crbug.com/713094 [ Win ] fast/css/fontfaceset-check-platform-fonts.html [ Failure Pass ]
 
+# Image decode failures due to document destruction.
+crbug.com/721435 external/wpt/image-decodes/image-decode-iframe.html [ Skip ]
+
 # Sheriff failures 2017-05-22
 crbug.com/725542 [ Debug ] editing/selection/doubleclick-beside-cr-span.html [ Pass Timeout ]
 crbug.com/725545 [ Debug ] fast/forms/number/number-stepup-stepdown-from-renderer.html [ Pass Timeout ]
diff --git a/third_party/WebKit/LayoutTests/accessibility/aom-string-properties.html b/third_party/WebKit/LayoutTests/accessibility/aom-string-properties.html
index 3e17d31..58524ee 100644
--- a/third_party/WebKit/LayoutTests/accessibility/aom-string-properties.html
+++ b/third_party/WebKit/LayoutTests/accessibility/aom-string-properties.html
@@ -35,23 +35,17 @@
 test(function(t) {
     var node = document.getElementById("checked");
     var axNode = accessibilityController.accessibleElementById("checked");
-    assert_equals(axNode.isChecked, false);
-    assert_equals(axNode.isButtonStateMixed, false);
+    assert_equals(axNode.checked, "false");
     node.accessibleNode.checked = "true";
-    assert_equals(axNode.isChecked, true);
-    assert_equals(axNode.isButtonStateMixed, false);
+    assert_equals(axNode.checked, "true");
     node.accessibleNode.checked = "mixed";
-    assert_equals(axNode.isChecked, true);
-    assert_equals(axNode.isButtonStateMixed, true);
+    assert_equals(axNode.checked, "mixed");
 
     // It also works to set it to just true or false (no quotes).
     node.accessibleNode.checked = true;
-    assert_equals(axNode.isChecked, true);
-    assert_equals(axNode.isButtonStateMixed, false);
+    assert_equals(axNode.checked, "true");
     node.accessibleNode.checked = false;
-    assert_equals(axNode.isChecked, false);
-    assert_equals(axNode.isButtonStateMixed, false);
-
+    assert_equals(axNode.checked, "false");
 }, "AccessibleNode.checked");
 </script>
 
diff --git a/third_party/WebKit/LayoutTests/accessibility/aria-checkbox-checked-expected.txt b/third_party/WebKit/LayoutTests/accessibility/aria-checkbox-checked-expected.txt
index a6acca42c..04a4c7a 100644
--- a/third_party/WebKit/LayoutTests/accessibility/aria-checkbox-checked-expected.txt
+++ b/third_party/WebKit/LayoutTests/accessibility/aria-checkbox-checked-expected.txt
@@ -7,14 +7,14 @@
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-PASS checkbox.isChecked is false
-PASS checkbox.isChecked is true
-PASS checkbox.isChecked is false
-PASS checkbox.isChecked is true
-PASS checkbox.isChecked is false
-PASS checkbox.isChecked is false
-PASS checkbox.isChecked is true
-PASS checkbox.isChecked is true
+PASS checkbox.checked is "false"
+PASS checkbox.checked is "true"
+PASS checkbox.checked is "false"
+PASS checkbox.checked is "true"
+PASS checkbox.checked is "false"
+PASS checkbox.checked is "false"
+PASS checkbox.checked is "true"
+PASS checkbox.checked is "true"
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/accessibility/aria-checkbox-checked-mixed.html b/third_party/WebKit/LayoutTests/accessibility/aria-checkbox-checked-mixed.html
index 4573fb72..0966981 100644
--- a/third_party/WebKit/LayoutTests/accessibility/aria-checkbox-checked-mixed.html
+++ b/third_party/WebKit/LayoutTests/accessibility/aria-checkbox-checked-mixed.html
@@ -29,7 +29,7 @@
         for (var i = 1; i <= 10; i++) {
             var element = accessibilityController.accessibleElementById("element" + i);
             debug("Role: " + element.role);
-            debug("Mixed: " + element.isButtonStateMixed);
+            debug("Mixed: " + (element.checked === 'mixed'));
         }
     }
 
diff --git a/third_party/WebKit/LayoutTests/accessibility/aria-checkbox-checked.html b/third_party/WebKit/LayoutTests/accessibility/aria-checkbox-checked.html
index 90cbc742..50f59dd 100644
--- a/third_party/WebKit/LayoutTests/accessibility/aria-checkbox-checked.html
+++ b/third_party/WebKit/LayoutTests/accessibility/aria-checkbox-checked.html
@@ -38,7 +38,7 @@
                 var checkbox = document.getElementById(answers[i][0]);
                 checkbox.focus();
                 checkbox = accessibilityController.focusedElement;
-                shouldBe("checkbox.isChecked", answers[i][1]);
+                shouldBeEqualToString("checkbox.checked", answers[i][1]);
           }
     }
 
diff --git a/third_party/WebKit/LayoutTests/accessibility/aria-treeitem-checkable.html b/third_party/WebKit/LayoutTests/accessibility/aria-treeitem-checkable.html
new file mode 100644
index 0000000..9caf2494
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/accessibility/aria-treeitem-checkable.html
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+
+<div role="treeitem" id="treeitem-uncheckable">Uncheckable</div>
+<div role="treeitem" id="treeitem-false" aria-checked="false">Not checked</div>
+<div role="treeitem" id="treeitem-true" aria-checked="true">Checked</div>
+<div role="treeitem" id="treeitem-mixed" aria-checked="mixed">Mixed</div>
+
+
+<script>
+function axElementById(id) {
+    return accessibilityController.accessibleElementById(id);
+}
+
+test(function(t) {
+    var treeItem = axElementById("treeitem-uncheckable");
+    assert_equals(treeItem.checked, "");
+}, "A tree item with no aria-checked has no checked property");
+
+test(function(t) {
+    var treeItem = axElementById("treeitem-false");
+    assert_equals(treeItem.checked, "false");
+}, "A tree item with aria-checked=false has checked=false");
+
+test(function(t) {
+    var treeItem = axElementById("treeitem-true");
+    assert_equals(treeItem.checked, "true");
+}, "A tree item with aria-checked=true has checked=true");
+
+test(function(t) {
+    var treeItem = axElementById("treeitem-mixed");
+    assert_equals(treeItem.checked, "mixed");
+}, "A tree item with aria-checked=mixed has checked=mixed");
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/accessibility/input-mixed.html b/third_party/WebKit/LayoutTests/accessibility/input-mixed.html
index 5f451fd..68e2f77 100644
--- a/third_party/WebKit/LayoutTests/accessibility/input-mixed.html
+++ b/third_party/WebKit/LayoutTests/accessibility/input-mixed.html
@@ -5,10 +5,10 @@
 <input id="element1" type="checkbox" />
 <script>
   // No way currently to do this via markup, must be via JS
-  document.getElementById('element1').indeterminate = true;
+  document.getElementById("element1").indeterminate = true;
 </script>
 <!-- Control-->
-<input id="element2" type="checkbox"  />
+<input id="element2" type="checkbox" />
 
 <div>
   <!-- Will be ::indeterminate in CSS because no radio item selected yet -->
@@ -22,6 +22,19 @@
   <input id="element5" type="radio" checked name="radiogroup2" />
 </div>
 
+<input id="input-button" type="button"/>
+<input id="input-button-false" type="button" aria-pressed="false"/>
+<input id="input-button-mixed" type="button" aria-pressed="mixed"/>
+<input id="input-button-true" type="button" aria-pressed="true"/>
+<div id="aria-button" role="button">button</div>
+<div id="aria-button-false" role="button" aria-pressed="false">button</div>
+<div id="aria-button-mixed" role="button" aria-pressed="mixed">button</div>
+<div id="aria-button-true" role="button" aria-pressed="true">button</div>
+<button id="button">button</button>
+<button id="button-false" aria-pressed="false">button</button>
+<button id="button-mixed" aria-pressed="mixed">button</button>
+<button id="button-true" aria-pressed="true">button</button>
+
 <script>
 
   function axElementById(id) {
@@ -30,29 +43,130 @@
 
   test(function(t) {
     var ax = axElementById("element1");
-    assert_true(ax.isButtonStateMixed);
+    assert_equals(ax.checked, "mixed");
   }, "A native indeterminate checkbox must have the mixed state");
 
   test(function(t) {
     var ax = axElementById("element2");
-    assert_false(ax.isButtonStateMixed);
+    assert_equals(ax.checked, "false");
   }, "A native checkbox that is not indeterminate" +
       " must NOT have the mixed state");
 
   test(function(t) {
     var ax = axElementById("element3");
-    assert_true(ax.isButtonStateMixed);
+    assert_equals(ax.checked, "mixed");
   }, "A native radio that in a group with nothing checked" +
       " must have the mixed state");
 
   test(function(t) {
     var ax = axElementById("element4");
-    assert_false(ax.isButtonStateMixed);
+    assert_equals(ax.checked, "false");
   }, "A native radio that in a group with something checked" +
       " must NOT have the mixed state");
 
   test(function(t) {
-    var ax = axElementById("element4");
-    assert_false(ax.isButtonStateMixed);
-  }, "A checked native radio must NOT have the mixed state");
+    var ax = axElementById("input-button");
+    assert_equals(ax.checked, "");
+  }, "<input type=button> does not set checked property");
+
+  test(function(t) {
+    var ax = axElementById("input-button-false");
+    assert_equals(ax.checked, "false");
+  }, "<input type=button aria-pressed=false> is not checked");
+
+  test(function(t) {
+    var ax = axElementById("input-button-false");
+    assert_equals(ax.role, "AXRole: AXToggleButton");
+  }, "<input type=button aria-pressed=false> is a toggle button");
+
+  test(function(t) {
+    var ax = axElementById("input-button-mixed");
+    assert_equals(ax.checked, "mixed");
+  }, "<input type=button aria-pressed=mixed> has checked state of mixed");
+
+  test(function(t) {
+    var ax = axElementById("input-button-mixed");
+    assert_equals(ax.role, "AXRole: AXToggleButton");
+  }, "<input type=button aria-pressed=mixed> is a toggle button");
+
+  test(function(t) {
+    var ax = axElementById("input-button-true");
+    assert_equals(ax.checked, "true");
+  }, "<input type=button aria-pressed=true> has checked state of true");
+
+  test(function(t) {
+    var ax = axElementById("input-button-true");
+    assert_equals(ax.role, "AXRole: AXToggleButton");
+  }, "<input type=button aria-pressed=true> is a toggle button");
+
+  test(function(t) {
+    var ax = axElementById("aria-button");
+    assert_equals(ax.checked, "");
+  }, "<div role=button> does not set checked property");
+
+  test(function(t) {
+    var ax = axElementById("aria-button-false");
+    assert_equals(ax.checked, "false");
+  }, "<div role=button aria-pressed=false> is not checked");
+
+  test(function(t) {
+    var ax = axElementById("aria-button-false");
+    assert_equals(ax.role, "AXRole: AXToggleButton");
+  }, "<div role=button aria-pressed=false> is a toggle button");
+
+  test(function(t) {
+    var ax = axElementById("aria-button-mixed");
+    assert_equals(ax.checked, "mixed");
+  }, "<div role=button aria-pressed=mixed> has checked state of mixed");
+
+  test(function(t) {
+    var ax = axElementById("aria-button-mixed");
+    assert_equals(ax.role, "AXRole: AXToggleButton");
+  }, "<div role=button aria-pressed=mixed> is a toggle button");
+
+  test(function(t) {
+    var ax = axElementById("aria-button-true");
+    assert_equals(ax.checked, "true");
+  }, "<div role=button aria-pressed=true> has checked state of true");
+
+  test(function(t) {
+    var ax = axElementById("aria-button-true");
+    assert_equals(ax.role, "AXRole: AXToggleButton");
+  }, "<div role=button aria-pressed=true> is a toggle button");
+
+  test(function(t) {
+    var ax = axElementById("button");
+    assert_equals(ax.checked, "");
+  }, "<button> does not set checked property");
+
+  test(function(t) {
+    var ax = axElementById("button-false");
+    assert_equals(ax.checked, "false");
+  }, "<button aria-pressed=false> is not checked");
+
+  test(function(t) {
+    var ax = axElementById("button-false");
+    assert_equals(ax.role, "AXRole: AXToggleButton");
+  }, "<button aria-pressed=false> is a toggle button");
+
+  test(function(t) {
+    var ax = axElementById("button-mixed");
+    assert_equals(ax.checked, "mixed");
+  }, "<button aria-pressed=mixed> has pressed state of checked");
+
+  test(function(t) {
+    var ax = axElementById("button-mixed");
+    assert_equals(ax.role, "AXRole: AXToggleButton");
+  }, "<button aria-pressed=mixed> is a toggle button");
+
+  test(function(t) {
+    var ax = axElementById("button-true");
+    assert_equals(ax.checked, "true");
+  }, "<button aria-pressed=true> has checked state of true");
+
+  test(function(t) {
+    var ax = axElementById("button-true");
+    assert_equals(ax.role, "AXRole: AXToggleButton");
+  }, "<button aria-pressed=true> is a toggle button");
+
 </script>
diff --git a/third_party/WebKit/LayoutTests/accessibility/option-aria-checked.html b/third_party/WebKit/LayoutTests/accessibility/option-aria-checked.html
index d109e09..714aa6d 100644
--- a/third_party/WebKit/LayoutTests/accessibility/option-aria-checked.html
+++ b/third_party/WebKit/LayoutTests/accessibility/option-aria-checked.html
@@ -7,9 +7,10 @@
 <option id="element2" role="menuitemcheckbox" aria-checked="true">2</option>
 <option id="element3" role="menuitemradio">3</option>
 <option id="element4" role="menuitemradio" aria-checked="true">4</option>
-<!-- Checked not supported -->
 <option id="element5" aria-checked="true">5</option>
 </select>
+<!-- Checked not supported -->
+<div id="element6" role="button" aria-checked="true">6</div>
 
 <script>
 
@@ -19,27 +20,32 @@
 
   test(function(t) {
     var ax = axElementById("element1");
-    assert_false(ax.isChecked);
+    assert_equals(ax.checked, "false");
   }, "<option> of role menuitemcheckbox is not checked by default");
 
   test(function(t) {
     var ax = axElementById("element2");
-    assert_true(ax.isChecked);
+    assert_equals(ax.checked, "true");
   }, "<option> of role menuitemcheckbox can be checked with aria-checked");
 
   test(function(t) {
     var ax = axElementById("element3");
-    assert_false(ax.isChecked);
+    assert_equals(ax.checked, "false");
   }, "<option> of role menuitemradio is not checked by default");
 
   test(function(t) {
     var ax = axElementById("element4");
-    assert_true(ax.isChecked);
+    assert_equals(ax.checked, "true");
   }, "<option> of role menuitemradio can be checked with aria-checked");
 
   test(function(t) {
     var ax = axElementById("element5");
-    assert_false(ax.isChecked);
-  }, "<option> of no role is not checked even with aria-checked set");
+    assert_equals(ax.checked, "true");
+  }, "<option> of no role is checked with aria-checked set");
+
+  test(function(t) {
+    var ax = axElementById("element6");
+    assert_equals(ax.checked, "");
+  }, "Element of button role does not expose checked even with aria-checked set");
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/css3/blending/background-blend-mode-gradient-color-expected.png b/third_party/WebKit/LayoutTests/css3/blending/background-blend-mode-gradient-color-expected.png
index cd96ae7..fb0b5d0 100644
--- a/third_party/WebKit/LayoutTests/css3/blending/background-blend-mode-gradient-color-expected.png
+++ b/third_party/WebKit/LayoutTests/css3/blending/background-blend-mode-gradient-color-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/css3/blending/background-blend-mode-gradient-gradient-expected.png b/third_party/WebKit/LayoutTests/css3/blending/background-blend-mode-gradient-gradient-expected.png
index 899a4c9..bde0f5a 100644
--- a/third_party/WebKit/LayoutTests/css3/blending/background-blend-mode-gradient-gradient-expected.png
+++ b/third_party/WebKit/LayoutTests/css3/blending/background-blend-mode-gradient-gradient-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/send-entity-body-document.htm b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/send-entity-body-document.htm
index 5f1cb68..ceafc48 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/send-entity-body-document.htm
+++ b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/send-entity-body-document.htm
@@ -29,7 +29,7 @@
           client.send(input)
           var exp = expectations[number]
           assert_equals(client.getResponseHeader('X-Request-Content-Type'), exp.contentType, 'document should be serialized and sent as '+exp.contentType+' (TEST#'+number+')')
-          // The indexOf() assertation will overlook some stuff, i.e. XML prologues that shouldn't be there (looking at you, Presto).
+          // The indexOf() assertion will overlook some stuff, i.e. XML prologues that shouldn't be there (looking at you, Presto).
           // However, arguably these things have little to do with the XHR functionality we're testing.
           if(exp.responseText){ // This test does not want to assert anything about what markup a standalone IMG should be wrapped in. Hence the GIF test lacks a responseText expectation.
             assert_true(client.responseText.indexOf(exp.responseText) != -1,
diff --git a/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/status-async.htm b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/status-async.htm
index dcf7d62..8e82701 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/status-async.htm
+++ b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/status-async.htm
@@ -52,7 +52,7 @@
       status(401, "OH HELLO", "Not today.", "")
       status(402, "FIVE BUCKS", "<x>402<\/x>", "text/xml")
       status(402, "FREE", "Nice!", "text/doesnotmatter")
-      status(402, "402 TEH AWESOME", "", "")
+      status(402, "402 THE AWESOME", "", "")
       status(502, "YO", "", "")
       status(502, "lowercase", "SWEET POTATO", "text/plain")
       status(503, "HOUSTON WE HAVE A", "503", "text/plain")
diff --git a/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/status-basic.htm b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/status-basic.htm
index fed7cabec..80147e8 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/status-basic.htm
+++ b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/status-basic.htm
@@ -41,7 +41,7 @@
       status(401, "OH HELLO", "Not today.", "")
       status(402, "FIVE BUCKS", "<x>402<\/x>", "text/xml")
       status(402, "FREE", "Nice!", "text/doesnotmatter")
-      status(402, "402 TEH AWESOME", "", "")
+      status(402, "402 THE AWESOME", "", "")
       status(502, "YO", "", "")
       status(502, "lowercase", "SWEET POTATO", "text/plain")
       status(503, "HOUSTON WE HAVE A", "503", "text/plain")
diff --git a/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/xmlhttprequest-basic.htm b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/xmlhttprequest-basic.htm
index c48b610f..1b9a36c 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/xmlhttprequest-basic.htm
+++ b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/xmlhttprequest-basic.htm
@@ -12,9 +12,9 @@
     <div id="log"></div>
     <script>
       test(function() {
-        XMLHttpRequest.prototype.test = function() { return "TEH" }
+        XMLHttpRequest.prototype.test = function() { return "THE" }
         var client = new XMLHttpRequest()
-        assert_equals(client.test(), "TEH")
+        assert_equals(client.test(), "THE")
         var members = ["onreadystatechange",
                        "open",
                        "setRequestHeader",
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/blink-contrib/inline-style-attribute-on-html.sub.html b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/blink-contrib/inline-style-attribute-on-html.sub.html
index b002af9..a0b9ed1c 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/blink-contrib/inline-style-attribute-on-html.sub.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/blink-contrib/inline-style-attribute-on-html.sub.html
@@ -15,7 +15,7 @@
 </head>
 
 <body>
-    <p>Even though this page has a CSP policy the blocks inline style, the style attribute on the HTML element still takes effect because it preceeds the meta element.
+    <p>Even though this page has a CSP policy the blocks inline style, the style attribute on the HTML element still takes effect because it precedes the meta element.
     </p>
     <script>
         log(document.documentElement.style.length > 0 ? 'PASS' : 'FAIL');
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/support/checkReport.sub.js b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/support/checkReport.sub.js
index 803dc06..ab52b7c 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/support/checkReport.sub.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/support/checkReport.sub.js
@@ -51,7 +51,7 @@
           }
           // Firefox expands 'self' or origins in a policy to the actual origin value
           // so "www.example.com" becomes "http://www.example.com:80".
-          // Accomodate this by just testing that the correct directive name
+          // Accommodate this by just testing that the correct directive name
           // is reported, not the details...
 
           if(data["csp-report"] != undefined && data["csp-report"][reportField] != undefined) {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/cors/redirect-preflight.htm b/third_party/WebKit/LayoutTests/external/wpt/cors/redirect-preflight.htm
index ff64284..f4af1243 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/cors/redirect-preflight.htm
+++ b/third_party/WebKit/LayoutTests/external/wpt/cors/redirect-preflight.htm
@@ -20,10 +20,10 @@
 var CROSSDOMAIN_URL = CROSSDOMAIN + 'resources/cors-makeheader.py?';
 
 /*
- * Redirection after successfull (200) preflight.
+ * Redirection after successful (200) preflight.
  */
 function redir_after_successfull_preflight(code) {
-  var desc = 'Should allow redirect ' + code + ' after succesful (200) preflight';
+  var desc = 'Should allow redirect ' + code + ' after successful (200) preflight';
   async_test(desc).step(function() {
     var client = new XMLHttpRequest();
     var redirect = encodeURIComponent(
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/floats-clear/margin-collapse-033.xht b/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/floats-clear/margin-collapse-033.xht
index 89c8af3..53c55c4 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/floats-clear/margin-collapse-033.xht
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/floats-clear/margin-collapse-033.xht
@@ -12,7 +12,7 @@
   <link rel="help" href="http://www.w3.org/TR/CSS21/visuren.html#flow-control" />
   <link rel="match" href="../reference/ref-filled-green-100px-square.xht" />
   <meta content="" name="flags" />
-  <meta content="Margin-top of following siblings of a block on which 'clear' has been set (to a different value than 'none') must not be substracted when calculating clearance. When an element's own margins collapse, and that element has had clearance applied to it, its top margin collapses with the adjoining margins of following siblings." name="assert" />
+  <meta content="Margin-top of following siblings of a block on which 'clear' has been set (to a different value than 'none') must not be subtracted when calculating clearance. When an element's own margins collapse, and that element has had clearance applied to it, its top margin collapses with the adjoining margins of following siblings." name="assert" />
 
   <style type="text/css"><![CDATA[
   div#overlapped-red
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/floats-clear/margin-collapse-034.xht b/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/floats-clear/margin-collapse-034.xht
index 17c11e5..3c0e1a36 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/floats-clear/margin-collapse-034.xht
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/floats-clear/margin-collapse-034.xht
@@ -12,7 +12,7 @@
   <link rel="help" href="http://www.w3.org/TR/CSS21/visuren.html#flow-control" />
   <link rel="match" href="../reference/ref-filled-green-100px-square.xht" />
   <meta content="" name="flags" />
-  <meta content="Margin-top of following siblings of a block on which 'clear' has been set (to a different value than 'none') must not be substracted when calculating clearance. When an element's own margins collapse, and that element has had clearance applied to it, its top margin collapses with the adjoining margins of following siblings." name="assert" />
+  <meta content="Margin-top of following siblings of a block on which 'clear' has been set (to a different value than 'none') must not be subtracted when calculating clearance. When an element's own margins collapse, and that element has had clearance applied to it, its top margin collapses with the adjoining margins of following siblings." name="assert" />
 
   <style type="text/css"><![CDATA[
   div#overlapped-red
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/floats-clear/margin-collapse-035.xht b/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/floats-clear/margin-collapse-035.xht
index 608bdd9..87b1b92 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/floats-clear/margin-collapse-035.xht
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/floats-clear/margin-collapse-035.xht
@@ -12,7 +12,7 @@
   <link rel="help" href="http://www.w3.org/TR/CSS21/visuren.html#flow-control" />
   <link rel="match" href="../reference/ref-filled-green-100px-square.xht" />
   <meta content="" name="flags" />
-  <meta content="Margin-top of following siblings of a block on which 'clear' has been set (to a different value than 'none') must not be substracted when calculating clearance. When an element's own margins collapse, and that element has had clearance applied to it, its top margin collapses with the adjoining margins of following siblings." name="assert" />
+  <meta content="Margin-top of following siblings of a block on which 'clear' has been set (to a different value than 'none') must not be subtracted when calculating clearance. When an element's own margins collapse, and that element has had clearance applied to it, its top margin collapses with the adjoining margins of following siblings." name="assert" />
 
   <style type="text/css"><![CDATA[
   div#overlapped-red
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/normal-flow/inline-block-005.xht b/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/normal-flow/inline-block-005.xht
index e710e49..bc41ad1 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/normal-flow/inline-block-005.xht
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/normal-flow/inline-block-005.xht
@@ -22,7 +22,7 @@
   line is short enough, should end up wrapping onto two lines internally. In addition
   each inline-block has 5em indentation on the left and 5em padding on the right,
   which should make no difference except that the boxes should be slightly wider than
-   <a href="002.html">before</a>. They shouldn't wrap particularily more than before.</p>
+   <a href="002.html">before</a>. They shouldn't wrap particularly more than before.</p>
   <p>
    <span>this is an inline-block this is an inline-block</span>
    <span>this is an inline-block this is an inline-block</span>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/normal-flow/max-height-111.xht b/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/normal-flow/max-height-111.xht
index 52af5a5ba..13cc8f3 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/normal-flow/max-height-111.xht
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/normal-flow/max-height-111.xht
@@ -11,7 +11,7 @@
   <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#min-max-heights" />
   <link rel="help" href="http://www.w3.org/TR/CSS21/visufx.html#overflow" />
   <meta content="ahem" name="flags" />
-  <meta content="The content of the #test-red-overlapped generates an active horizontal scrollbar. The height of such horizontal scrollbar adds itself to the content making it exceed the max-height constraint of 200px. Therefore, such vertical space taken by the horizontal scrollbar must be substracted from the height of the content. An active vertical scrollbar then must be generated to provide access to the equivalent of the height of the horizontal scrollbar." name="assert" />
+  <meta content="The content of the #test-red-overlapped generates an active horizontal scrollbar. The height of such horizontal scrollbar adds itself to the content making it exceed the max-height constraint of 200px. Therefore, such vertical space taken by the horizontal scrollbar must be subtracted from the height of the content. An active vertical scrollbar then must be generated to provide access to the equivalent of the height of the horizontal scrollbar." name="assert" />
 
   <style type="text/css"><![CDATA[
   div
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/grid-definition/fr-unit-with-percentage.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/grid-definition/fr-unit-with-percentage.html
index 9e6ec9f..82c97ab 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/grid-definition/fr-unit-with-percentage.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/grid-definition/fr-unit-with-percentage.html
@@ -1,7 +1,7 @@
 <!DOCTYPE HTML>
 <html>
 <head>
-  <title>CSS3 Grid Layout: Flexible Lenght</title>
+  <title>CSS3 Grid Layout: Flexible Length</title>
   <link rel="author" title="swain" href="mailto:swainet@126.com"/>
   <link rel="reviewer" title="Dayang Shen" href="mailto:shendayang@baidu.com"/> <!-- 2013-09-22 -->
   <link rel="help" href="http://www.w3.org/TR/css-grid-1/#fr-unit"/>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-position-3/position-sticky-get-bounding-client-rect.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-position-3/position-sticky-get-bounding-client-rect.html
new file mode 100644
index 0000000..a664ab3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-position-3/position-sticky-get-bounding-client-rect.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<title>Sticky positioned element should be observable by getBoundingClientRect.</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that sticky positioned element
+should be observable by getBoundingClientRect." />
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+body {
+  margin: 0;
+}
+
+.container {
+  overflow: scroll;
+  width: 200px;
+  height: 200px;
+}
+
+.spacer {
+  height: 2000px;
+}
+
+.box {
+  width: 100px;
+  height: 100px;
+  background-color: green;
+  top: 50px;
+}
+
+.sticky {
+  position: sticky;
+}
+</style>
+
+<div id="scroller" class="container">
+  <div id="sticky" class="sticky box"></div>
+  <div class="spacer"></div>
+</div>
+
+<script>
+test(() => {
+  var element = document.getElementById('sticky');
+  assert_equals(element.getBoundingClientRect().top, 50);
+  document.getElementById('scroller').scrollTop = 100;
+  assert_equals(element.getBoundingClientRect().top, 50);
+  sticky.style.position = 'relative';
+  assert_equals(element.getBoundingClientRect().top, -50);
+  sticky.style.position = 'sticky';
+  assert_equals(element.getBoundingClientRect().top, 50);
+}, 'sticky positioned element should be observable by getBoundingClientRect.');
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/line-height-step-parsing-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/line-height-step-parsing-001.html
index 3febf05..7d45d598 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/line-height-step-parsing-001.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/line-height-step-parsing-001.html
@@ -17,7 +17,7 @@
 
   <div title="'0' should be a valid length" style="line-height-step: 0" data-expected="0px"></div>
 
-  <div title="Interger should be invalid" style="line-height-step: 1" data-expected="20px"></div>
+  <div title="Integer should be invalid" style="line-height-step: 1" data-expected="20px"></div>
   <div title="Negative length should be invalid" style="line-height-step: -1px" data-expected="20px"></div>
 </div>
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes-1/shape-outside/supported-shapes/polygon/shape-outside-polygon-015.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes-1/shape-outside/supported-shapes/polygon/shape-outside-polygon-015.html
index 084f060..8338c6c 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes-1/shape-outside/supported-shapes/polygon/shape-outside-polygon-015.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes-1/shape-outside/supported-shapes/polygon/shape-outside-polygon-015.html
@@ -10,7 +10,7 @@
         <meta name="flags" content="ahem" />
         <meta name="assert" content="The test verifies that text wraps around a
                                      right float with a shape-outside defined as
-                                     an polygon from the content box wtih a shape margin.">
+                                     an polygon from the content box with a shape margin.">
     </head>
     <style>
         body {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes-1/shape-outside/values/shape-outside-shape-none-000.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes-1/shape-outside/values/shape-outside-shape-none-000.html
index 9f7ffce2..b3a5e15 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes-1/shape-outside/values/shape-outside-shape-none-000.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes-1/shape-outside/values/shape-outside-shape-none-000.html
@@ -6,7 +6,7 @@
         <link rel="author" title="Rebecca Hauck" href="mailto:rhauck@adobe.com">
         <link rel="reviewer" title="Alan Stearns" href="mailto:stearns@adobe.com"> <!-- 2014-03-04 -->
         <link rel="help" href="http://www.w3.org/TR/css-shapes-1/#shape-outside-property">
-        <meta name="assert" content="shape-outside can be explictly assigned the default value of none.">
+        <meta name="assert" content="shape-outside can be explicitly assigned the default value of none.">
         <meta name="flags" content="dom">
         <script src="/resources/testharness.js"></script>
         <script src="/resources/testharnessreport.js"></script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms-2/rotateY.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms-2/rotateY.html
index 593969a7..a90b749 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms-2/rotateY.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms-2/rotateY.html
@@ -6,7 +6,7 @@
     <link rel="reviewer" title="Dayang Shen" href="mailto:shendayang@baidu.com"> <!-- 2013-09-05 -->
     <link rel="help" href="http://www.w3.org/TR/css-transforms-2/#funcdef-rotatey">
     <link rel="match" href="reference/rotateY-ref.html">
-    <meta name="assert" content="When the value of transform is 'rotateY(90deg)', the foward side of a transformed element disappears.">
+    <meta name="assert" content="When the value of transform is 'rotateY(90deg)', the forward side of a transformed element disappears.">
     <style type="text/css">
         .greenSquare {
             position: absolute;
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/box-sizing-007.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/box-sizing-007.html
index c51f431..74fee24 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/box-sizing-007.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/box-sizing-007.html
@@ -7,7 +7,7 @@
 <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#inline-replaced-height">
 <meta name="flags" content="svg">
 <link rel="match" href="reference/box-sizing-007-ref.html">
-<meta name="assert" content="Exercises the sizing rules in CSS2.1 10.3.2 and 10.6.2 with box-sizing:border-box for replaced elements with either both intrisic dimentions or an intrinsic ratio, to check that they work correctly in terms of the content width height.">
+<meta name="assert" content="Exercises the sizing rules in CSS2.1 10.3.2 and 10.6.2 with box-sizing:border-box for replaced elements with either both intrisic dimensions or an intrinsic ratio, to check that they work correctly in terms of the content width height.">
 <style>
 img {
 	box-sizing: border-box;
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/nav-dir-missing-1.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/nav-dir-missing-1.html
index 7d2b760..52d396b 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/nav-dir-missing-1.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/nav-dir-missing-1.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<title>CSS Basic User Interface Test: Directional Focus Navigation - unkown element id</title>
+<title>CSS Basic User Interface Test: Directional Focus Navigation - unknown element id</title>
 <link rel="author" title="Florian Rivoal" href="mailto:florian@rivoal.net">
 <link rel="help" href="http://www.w3.org/TR/css3-ui/#nav-dir">
 <meta name="flags" content="interact">
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/nav-dir-missing-2.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/nav-dir-missing-2.html
index a4cd062..b827ccb 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/nav-dir-missing-2.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/nav-dir-missing-2.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<title>CSS Basic User Interface Test: Directional Focus Navigation - unkown element id</title>
+<title>CSS Basic User Interface Test: Directional Focus Navigation - unknown element id</title>
 <link rel="author" title="Florian Rivoal" href="mailto:florian@rivoal.net">
 <link rel="help" href="http://www.w3.org/TR/css3-ui/#nav-dir">
 <meta name="flags" content="interact">
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/nav-dir-missing-3.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/nav-dir-missing-3.html
index ea424c1..7e6c1c9 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/nav-dir-missing-3.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/nav-dir-missing-3.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<title>CSS Basic User Interface Test: Directional Focus Navigation - unkown element id</title>
+<title>CSS Basic User Interface Test: Directional Focus Navigation - unknown element id</title>
 <link rel="author" title="Florian Rivoal" href="mailto:florian@rivoal.net">
 <link rel="help" href="http://www.w3.org/TR/css3-ui/#nav-dir">
 <meta name="flags" content="interact">
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/nav-dir-missing-4.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/nav-dir-missing-4.html
index 25d2552..933adfc1 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/nav-dir-missing-4.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/nav-dir-missing-4.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<title>CSS Basic User Interface Test: Directional Focus Navigation - unkown element id</title>
+<title>CSS Basic User Interface Test: Directional Focus Navigation - unknown element id</title>
 <link rel="author" title="Florian Rivoal" href="mailto:florian@rivoal.net">
 <link rel="help" href="http://www.w3.org/TR/css3-ui/#nav-dir">
 <meta name="flags" content="interact">
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/text-overflow-005.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/text-overflow-005.html
index e50a802..aae60cf35 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/text-overflow-005.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/text-overflow-005.html
@@ -2,7 +2,7 @@
 <html class="reftest-wait">
 <meta charset="utf-8">
 <title>CSS-UI test: text-overflow reflow</title>
-<meta name="assert" content="Text overflow should disappear when the container becomes large enough. This test is targetted at bug #14952 in Servo's incremental reflow engine.">
+<meta name="assert" content="Text overflow should disappear when the container becomes large enough. This test is targeted at bug #14952 in Servo's incremental reflow engine.">
 <link rel="author" title="Michael Howell" href="mailto:michael@notriddle.com">
 <link rel="help" title="8.2. Overflow Ellipsis: the 'text-overflow' property" href="http://www.w3.org/TR/css3-ui/#text-overflow">
 <link rel="match" href="reference/text-overflow-005-ref.html">
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/contiguous-floated-table-vlr-007.xht b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/contiguous-floated-table-vlr-007.xht
index 34faf64..a02689e 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/contiguous-floated-table-vlr-007.xht
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/contiguous-floated-table-vlr-007.xht
@@ -16,7 +16,7 @@
   <link rel="match" href="../reference/ref-filled-green-100px-square.xht" />
 
   <meta content="image" name="flags" />
-  <meta content="This test checks that horizontal margins existing between contiguous floated tables with writing-mode set to 'vertical-lr' are not substracted by the amount of their borders. In this test, there should be an horizontal gap of 50px separating both tables. Margins between 2 floated boxes do not collapse." name="assert" />
+  <meta content="This test checks that horizontal margins existing between contiguous floated tables with writing-mode set to 'vertical-lr' are not subtracted by the amount of their borders. In this test, there should be an horizontal gap of 50px separating both tables. Margins between 2 floated boxes do not collapse." name="assert" />
 
   <style type="text/css"><![CDATA[
   table
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/contiguous-floated-table-vlr-009.xht b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/contiguous-floated-table-vlr-009.xht
index 39fd43e0..1679dae 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/contiguous-floated-table-vlr-009.xht
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/contiguous-floated-table-vlr-009.xht
@@ -16,7 +16,7 @@
   <link rel="match" href="../reference/ref-filled-green-100px-square.xht" />
 
   <meta content="image" name="flags" />
-  <meta content="This test checks that horizontal margins existing between contiguous floated tables with writing-mode set to 'vertical-lr' are not substracted by the amount of their horizontal padding. In this test, there should be an horizontal gap of 50px separating both tables. Margins between 2 floated boxes do not collapse." name="assert" />
+  <meta content="This test checks that horizontal margins existing between contiguous floated tables with writing-mode set to 'vertical-lr' are not subtracted by the amount of their horizontal padding. In this test, there should be an horizontal gap of 50px separating both tables. Margins between 2 floated boxes do not collapse." name="assert" />
 
   <style type="text/css"><![CDATA[
   table
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/contiguous-floated-table-vrl-006.xht b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/contiguous-floated-table-vrl-006.xht
index d973517..52ecdebc 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/contiguous-floated-table-vrl-006.xht
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/contiguous-floated-table-vrl-006.xht
@@ -16,7 +16,7 @@
   <link rel="match" href="../reference/ref-filled-green-100px-square.xht" />
 
   <meta content="image" name="flags" />
-  <meta content="This test checks that horizontal margins existing between contiguous floated tables with writing-mode set to 'vertical-rl' are not substracted by the amount of their borders. In this test, there should be an horizontal gap of 50px separating both tables. Margins between 2 floated boxes do not collapse." name="assert" />
+  <meta content="This test checks that horizontal margins existing between contiguous floated tables with writing-mode set to 'vertical-rl' are not subtracted by the amount of their borders. In this test, there should be an horizontal gap of 50px separating both tables. Margins between 2 floated boxes do not collapse." name="assert" />
 
   <style type="text/css"><![CDATA[
   table
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/contiguous-floated-table-vrl-008.xht b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/contiguous-floated-table-vrl-008.xht
index 625f2c4..24c1009 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/contiguous-floated-table-vrl-008.xht
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/contiguous-floated-table-vrl-008.xht
@@ -16,7 +16,7 @@
   <link rel="match" href="../reference/ref-filled-green-100px-square.xht" />
 
   <meta content="image" name="flags" />
-  <meta content="This test checks that horizontal margins existing between contiguous floated tables with writing-mode set to 'vertical-rl' are not substracted by the amount of their horizontal padding. In this test, there should be an horizontal gap of 50px separating both tables. Margins between 2 floated boxes do not collapse." name="assert" />
+  <meta content="This test checks that horizontal margins existing between contiguous floated tables with writing-mode set to 'vertical-rl' are not subtracted by the amount of their horizontal padding. In this test, there should be an horizontal gap of 50px separating both tables. Margins between 2 floated boxes do not collapse." name="assert" />
 
   <style type="text/css"><![CDATA[
   table
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vlr-003.xht b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vlr-003.xht
index 263d55d..2dda421 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vlr-003.xht
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vlr-003.xht
@@ -17,7 +17,7 @@
   <link rel="match" href="line-box-height-vlr-003-ref.xht" />
 
   <meta content="" name="flags" />
-  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a border. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accomodate transparent 'border-left' of inline box and transparent 'border-right' of inline box." name="assert" />
+  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a border. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accommodate transparent 'border-left' of inline box and transparent 'border-right' of inline box." name="assert" />
 
   <style type="text/css"><![CDATA[
   body
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vlr-005.xht b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vlr-005.xht
index 32e2ddca..a0e8943 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vlr-005.xht
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vlr-005.xht
@@ -17,7 +17,7 @@
   <link rel="match" href="line-box-height-vlr-003-ref.xht" />
 
   <meta content="" name="flags" />
-  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a padding. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accomodate transparent 'padding-left' of inline box and transparent 'padding-right' of inline box." name="assert" />
+  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a padding. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accommodate transparent 'padding-left' of inline box and transparent 'padding-right' of inline box." name="assert" />
 
   <style type="text/css"><![CDATA[
   body
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vlr-007.xht b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vlr-007.xht
index c1f3e12..c43d7d2 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vlr-007.xht
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vlr-007.xht
@@ -17,7 +17,7 @@
   <link rel="match" href="line-box-height-vlr-007-ref.xht" />
 
   <meta content="" name="flags" />
-  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a border. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accomodate transparent 'border-left' of inline box and transparent 'border-right' of inline box." name="assert" />
+  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a border. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accommodate transparent 'border-left' of inline box and transparent 'border-right' of inline box." name="assert" />
 
   <style type="text/css"><![CDATA[
   body
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vlr-009.xht b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vlr-009.xht
index 1c63169..746fab5 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vlr-009.xht
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vlr-009.xht
@@ -17,7 +17,7 @@
   <link rel="match" href="line-box-height-vlr-007-ref.xht" />
 
   <meta content="" name="flags" />
-  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a padding. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accomodate transparent 'padding-left' of inline box and transparent 'padding-right' of inline box." name="assert" />
+  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a padding. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accommodate transparent 'padding-left' of inline box and transparent 'padding-right' of inline box." name="assert" />
 
   <style type="text/css"><![CDATA[
   body
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vlr-011.xht b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vlr-011.xht
index 953c7f0..db8eb01 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vlr-011.xht
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vlr-011.xht
@@ -17,7 +17,7 @@
   <link rel="match" href="line-box-height-vlr-011-ref.xht" />
 
   <meta content="" name="flags" />
-  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a border. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accomodate transparent 'border-left' of inline box and transparent 'border-right' of inline box." name="assert" />
+  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a border. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accommodate transparent 'border-left' of inline box and transparent 'border-right' of inline box." name="assert" />
 
   <style type="text/css"><![CDATA[
   body
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vlr-013.xht b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vlr-013.xht
index b4c56d52..7721919 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vlr-013.xht
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vlr-013.xht
@@ -17,7 +17,7 @@
   <link rel="match" href="line-box-height-vlr-011-ref.xht" />
 
   <meta content="" name="flags" />
-  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a padding. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accomodate transparent 'padding-left' of inline box and transparent 'padding-right' of inline box." name="assert" />
+  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a padding. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accommodate transparent 'padding-left' of inline box and transparent 'padding-right' of inline box." name="assert" />
 
   <style type="text/css"><![CDATA[
   body
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vlr-021.xht b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vlr-021.xht
index 8f1b60c7..4da9a5f 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vlr-021.xht
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vlr-021.xht
@@ -17,7 +17,7 @@
   <link rel="match" href="line-box-height-vlr-021-ref.xht" />
 
   <meta content="" name="flags" />
-  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a border. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accomodate transparent 'border-left' of inline box and transparent 'border-right' of inline box." name="assert" />
+  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a border. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accommodate transparent 'border-left' of inline box and transparent 'border-right' of inline box." name="assert" />
   <meta name="DC.date.created" content="2015-07-22T09:54:03+11:00" scheme=
   "W3CDTF" />
   <meta name="DC.date.modified" content="2016-07-22T09:54:03+11:00" scheme=
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vlr-023.xht b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vlr-023.xht
index 802a3fd..ae5a2f53 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vlr-023.xht
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vlr-023.xht
@@ -17,7 +17,7 @@
   <link rel="match" href="line-box-height-vlr-023-ref.xht" />
 
   <meta content="" name="flags" />
-  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a border. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accomodate transparent 'border-left' of inline box and transparent 'border-right' of inline box." name="assert" />
+  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a border. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accommodate transparent 'border-left' of inline box and transparent 'border-right' of inline box." name="assert" />
   <meta name="DC.date.created" content="2015-07-22T09:54:03+11:00" scheme="W3CDTF" />
   <meta name="DC.date.modified" content="2016-07-22T09:54:03+11:00" scheme="W3CDTF" />
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vrl-002.xht b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vrl-002.xht
index 1c57284..422f7d7 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vrl-002.xht
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vrl-002.xht
@@ -17,7 +17,7 @@
   <link rel="match" href="line-box-height-vrl-002-ref.xht" />
 
   <meta content="" name="flags" />
-  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a border. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accomodate transparent 'border-left' of inline box and transparent 'border-right' of inline box." name="assert" />
+  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a border. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accommodate transparent 'border-left' of inline box and transparent 'border-right' of inline box." name="assert" />
 
   <style type="text/css"><![CDATA[
   body
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vrl-004.xht b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vrl-004.xht
index 558d7a2..4f3f06f 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vrl-004.xht
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vrl-004.xht
@@ -17,7 +17,7 @@
   <link rel="match" href="line-box-height-vrl-002-ref.xht" />
 
   <meta content="" name="flags" />
-  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a padding. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accomodate transparent 'padding-left' of inline box and transparent 'padding-right' of inline box." name="assert" />
+  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a padding. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accommodate transparent 'padding-left' of inline box and transparent 'padding-right' of inline box." name="assert" />
 
   <style type="text/css"><![CDATA[
   body
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vrl-006.xht b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vrl-006.xht
index f49258d..0776ff92 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vrl-006.xht
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vrl-006.xht
@@ -17,7 +17,7 @@
   <link rel="match" href="line-box-height-vrl-006-ref.xht" />
 
   <meta content="" name="flags" />
-  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a border. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accomodate transparent 'border-left' of inline box and transparent 'border-right' of inline box." name="assert" />
+  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a border. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accommodate transparent 'border-left' of inline box and transparent 'border-right' of inline box." name="assert" />
 
   <style type="text/css"><![CDATA[
   body
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vrl-008.xht b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vrl-008.xht
index c273333..69485d7 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vrl-008.xht
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vrl-008.xht
@@ -17,7 +17,7 @@
   <link rel="match" href="line-box-height-vrl-006-ref.xht" />
 
   <meta content="" name="flags" />
-  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a padding. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accomodate transparent 'padding-left' of inline box and transparent 'padding-right' of inline box." name="assert" />
+  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a padding. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accommodate transparent 'padding-left' of inline box and transparent 'padding-right' of inline box." name="assert" />
 
   <style type="text/css"><![CDATA[
   body
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vrl-010.xht b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vrl-010.xht
index db85b1d3..ca6f77d8 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vrl-010.xht
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vrl-010.xht
@@ -17,7 +17,7 @@
   <link rel="match" href="line-box-height-vrl-010-ref.xht" />
 
   <meta content="" name="flags" />
-  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a border. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accomodate transparent 'border-left' of inline box and transparent 'border-right' of inline box." name="assert" />
+  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a border. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accommodate transparent 'border-left' of inline box and transparent 'border-right' of inline box." name="assert" />
 
   <style type="text/css"><![CDATA[
   body
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vrl-012.xht b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vrl-012.xht
index dac6eef..9376aee0 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vrl-012.xht
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/line-box-height-vrl-012.xht
@@ -17,7 +17,7 @@
   <link rel="match" href="line-box-height-vrl-010-ref.xht" />
 
   <meta content="" name="flags" />
-  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a padding. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accomodate transparent 'padding-left' of inline box and transparent 'padding-right' of inline box." name="assert" />
+  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a padding. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accommodate transparent 'padding-left' of inline box and transparent 'padding-right' of inline box." name="assert" />
 
   <style type="text/css"><![CDATA[
   body
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/variables/variable-supports-13.html b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/variables/variable-supports-13.html
index d6e8a68..83b3d04b 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/variables/variable-supports-13.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/variables/variable-supports-13.html
@@ -9,7 +9,7 @@
 <link rel="match" href="support/color-green-ref.html">
 <style>
 body { color: red; }
-@supports (color: something 3px url(whereever) calc(var(--a) + 1px)) {
+@supports (color: something 3px url(wherever) calc(var(--a) + 1px)) {
   p { color: green; }
 }
 </style>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/variables/variable-supports-45.html b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/variables/variable-supports-45.html
index 24b1eec..9f913f3d 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/variables/variable-supports-45.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/variables/variable-supports-45.html
@@ -9,7 +9,7 @@
 <link rel="match" href="support/color-green-ref.html">
 <style>
 body { color: red; }
-@supports (--a: something 3px url(whereever) calc(var(--b) + 1px)) {
+@supports (--a: something 3px url(wherever) calc(var(--b) + 1px)) {
   p { color: green; }
 }
 </style>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/domparsing/DOMParser-parseFromString-xml-doctype.html b/third_party/WebKit/LayoutTests/external/wpt/domparsing/DOMParser-parseFromString-xml-doctype.html
index cd655acf..2711308 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/domparsing/DOMParser-parseFromString-xml-doctype.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/domparsing/DOMParser-parseFromString-xml-doctype.html
@@ -10,7 +10,7 @@
     var doc = new DOMParser().parseFromString('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"><html><div id="test"/></html>', 'application/xhtml+xml');
     var div = doc.getElementById('test');
     assert_equals(div, null); // If null, then this was a an error document (didn't parse the input successfully)
-  }, "Doctype parsing of System Id must fail on ommitted value");
+  }, "Doctype parsing of System Id must fail on omitted value");
 
   test(function () {
     var doc = new DOMParser().parseFromString('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" ""><html><div id="test"/></html>', 'application/xhtml+xml');
diff --git a/third_party/WebKit/LayoutTests/external/wpt/encrypted-media/idlharness.html b/third_party/WebKit/LayoutTests/external/wpt/encrypted-media/idlharness.html
index e65ad5e3..fd74d1ab 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/encrypted-media/idlharness.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/encrypted-media/idlharness.html
@@ -2,7 +2,7 @@
 <html>
   <head>
     <meta charset=utf-8>
-    <title>Encrypted Media Extentions IDL test</title>
+    <title>Encrypted Media Extensions IDL test</title>
     <link rel="help" href="https://w3c.github.io/encrypted-media/">
 
     <script src=/resources/testharness.js></script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/response/response-clone-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/response/response-clone-expected.txt
index ec49708..8982a2b 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/response/response-clone-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/response/response-clone-expected.txt
@@ -1,7 +1,7 @@
 This is a testharness.js-based test.
 PASS Check Response's clone with default values, without body 
 PASS Check Response's clone has the expected attribute values 
-PASS Check orginal response's body after cloning 
+PASS Check original response's body after cloning 
 PASS Check cloned response's body 
 PASS Cannot clone a disturbed response 
 PASS Cloned responses should provide the same data 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/response/response-clone.html b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/response/response-clone.html
index 2eeb78c4..c4248e76 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/response/response-clone.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/response/response-clone.html
@@ -47,7 +47,7 @@
 
       promise_test(function(test) {
         return validateStreamFromString(response.body.getReader(), body);
-      }, "Check orginal response's body after cloning");
+      }, "Check original response's body after cloning");
 
       promise_test(function(test) {
         return validateStreamFromString(clonedResponse.body.getReader(), body);
diff --git a/third_party/WebKit/LayoutTests/external/wpt/geolocation-API/support.js b/third_party/WebKit/LayoutTests/external/wpt/geolocation-API/support.js
index 960b572..0f0e7f65 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/geolocation-API/support.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/geolocation-API/support.js
@@ -5,7 +5,7 @@
 });
 
 // The spec states that an implementation SHOULD acquire user permission before
-// beggining the position acquisition steps. If an implementation follows this
+// beginning the position acquisition steps. If an implementation follows this
 // advice, set the following flag to aid debugging.
 var isUsingPreemptivePermission = false;
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/README b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/README
index aeda217..451e8ac4 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/README
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/README
@@ -4,14 +4,14 @@
   http://dev.w3.org/html5/spec/dnd.html#dnd
 
 Tests in target-origin/ relate to a proposed spec extension and are not covered
-by HTML5 drafts at the time of writing. Contact Opera Sofware for details, and
+by HTML5 drafts at the time of writing. Contact Opera Software for details, and
 mention CT-1656.
 
 Tests in synthetic/ relate to incomplete parts of the HTML5 specification,
 which allows synthetic events to be created. For compatibility with others,
 the dataTransfer parameter allows null, undefined and other objects. Objects
 will create a synthetic dataTransfer. To provide maximum functionality,
-synthetic dataTransfer will have its own synthetic data store, detatched from
+synthetic dataTransfer will have its own synthetic data store, detached from
 the real data store used by real drag events (actual user interaction). For
 security, real dataTransfer objects will remember the real event's protection
 status inside synthetic events (the spec bases their protection only on the
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/events/events-cross-document-suite-HELPER-1.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/events/events-cross-document-suite-HELPER-1.html
index efd53c6b..6b6c80a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/events/events-cross-document-suite-HELPER-1.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/events/events-cross-document-suite-HELPER-1.html
@@ -70,7 +70,7 @@
 		/*
 			Normalise; reduce repeating event sequences to only 2 occurrences.
 			This makes the final event sequence predictable, no matter how many times the drag->dragover sequences repeat.
-			Two occurrances are kept in each case to allow testing to make sure the sequence really is repeating.
+			Two occurrences are kept in each case to allow testing to make sure the sequence really is repeating.
 		*/
 		//spec compliant - div dragenter is not cancelled, so body dragenter fires and body becomes current target
 		//repeats while drag is over orange or fuchsia or the body
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/remove/022-1.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/remove/022-1.html
index fe65c604..d2d954f 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/remove/022-1.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/remove/022-1.html
@@ -1,5 +1,5 @@
 <!doctype html>
-<title>Removing drop targetted document before the queue is processed</title>
+<title>Removing drop targeted document before the queue is processed</title>
 <style>
   html, body, div {
     height: 100%;
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/remove/022.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/remove/022.html
index 6bb8e6a..05661a1 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/remove/022.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/remove/022.html
@@ -1,5 +1,5 @@
 <!doctype html>
-<title>Removing drop targetted document before the queue is processed</title>
+<title>Removing drop targeted document before the queue is processed</title>
 <style>
   span, iframe {
     height: 200px;
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/audio_volume_check.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/audio_volume_check.html
index b467c702..4d7a6fe 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/audio_volume_check.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/audio_volume_check.html
@@ -24,7 +24,7 @@
 
         test(function() {
             assert_false(media.volume < VOLUME.SILENT || media.volume > VOLUME.LOUDEST, "media.volume outside the range 0.0 to 1.0 inclusive");
-        }, "Check if the intial value of the audio.volume is in the range 0.0 to 1.0 inclusive");
+        }, "Check if the initial value of the audio.volume is in the range 0.0 to 1.0 inclusive");
 
         function volume_setting(vol, name)
         {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/video_volume_check.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/video_volume_check.html
index 1a45358a..12deed9 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/video_volume_check.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/video_volume_check.html
@@ -24,7 +24,7 @@
 
         test(function() {
             assert_false(media.volume < VOLUME.SILENT || media.volume > VOLUME.LOUDEST, "media.volume outside the range 0.0 to 1.0 inclusive");
-        }, "Check if the intial value of the video.volume is in the range 0.0 to 1.0 inclusive");
+        }, "Check if the initial value of the video.volume is in the range 0.0 to 1.0 inclusive");
 
         function volume_setting(vol, name)
         {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-label-element/label-attributes.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-label-element/label-attributes.html
index 826533e..7bf5df3 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-label-element/label-attributes.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-label-element/label-attributes.html
@@ -116,7 +116,7 @@
     assert_equals(document.getElementById("test5").labels.length, 0,
                   "The number of labels should be 0 if the form control has an ancestor label element that the for attribute points to another control.");
     assert_equals(document.getElementById("lbl2").control, null,
-                  "The labeled cotrol should be associated with the control whose ID is equal to the value of the 'for' attribute.");
+                  "The labeled control should be associated with the control whose ID is equal to the value of the 'for' attribute.");
   }, "A form control has no label 2.");
 
   // form attribute
diff --git a/third_party/WebKit/LayoutTests/external/wpt/image-decodes/image-decode-iframe.html b/third_party/WebKit/LayoutTests/external/wpt/image-decodes/image-decode-iframe.html
new file mode 100644
index 0000000..e64ea98a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/image-decodes/image-decode-iframe.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>img.decode()</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel=help href="">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+
+<iframe id="frame_loaded" srcdoc="iframe"></iframe>
+<iframe id="frame_notloaded" srcdoc="iframe"></iframe>
+<iframe id="frame_notloaded2" srcdoc="iframe"></iframe>
+
+<script>
+"use strict";
+
+promise_test(function() {
+  return new Promise(function(resolve, reject) {
+    var frame = document.getElementById("frame_loaded");
+    var img = frame.contentDocument.createElement("img");
+    img.src = "/images/green.png";
+    img.onload = function() {
+      // At this point the frame which created the img is removed, so decode() should fail.
+      frame.parentNode.removeChild(frame);
+      img.decode().then(function() {
+        assert_false(true, "Unexpected success");
+      }, function() {
+        resolve();
+      });
+    };
+  });
+}, "(misc) Decode from removed iframe fails (loaded img)");
+
+promise_test(function(t) {
+  var frame = document.getElementById("frame_notloaded");
+  var img = frame.contentDocument.createElement("img");
+  img.src = "/images/green.png";
+  frame.parentNode.removeChild(frame);
+  var promise = img.decode();
+  return promise_rejects(t, "EncodingError", promise);
+}, "(misc) Decode from removed iframe fails (img not loaded)");
+
+promise_test(function(t) {
+  var frame = document.getElementById("frame_notloaded2");
+  var img = frame.contentDocument.createElement("img");
+  img.src = "/images/green.png";
+  // First request a promise, then remove the iframe.
+  var promise = img.decode();
+  frame.parentNode.removeChild(frame);
+  return promise_rejects(t, "EncodingError", promise);
+}, "(misc) Decode from iframe, later removed, fails (img not loaded)");
+
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/image-decodes/image-decode-path-changes.html b/third_party/WebKit/LayoutTests/external/wpt/image-decodes/image-decode-path-changes.html
new file mode 100644
index 0000000..6082c4b1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/image-decodes/image-decode-path-changes.html
@@ -0,0 +1,112 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>img.decode()</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel=help href="">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+
+<script>
+"use strict";
+
+// src tests
+// -------------------
+promise_test(function(t) {
+  var img = new Image();
+  img.src = "/images/green.png";
+  var promise = img.decode();
+  img.src = "/images/green.svg";
+  return promise_rejects(t, "EncodingError", promise);
+}, "(src) Path changes fail decode.");
+
+promise_test(function(t) {
+  var img = new Image();
+  img.src = "/images/green.png";
+  var first_promise = img.decode();
+  img.src = "/images/green.svg";
+  var second_promise = img.decode();
+  assert_true(first_promise !== second_promise);
+  return Promise.all([
+    promise_rejects(t, "EncodingError", first_promise),
+    second_promise
+  ]);
+}, "(src) Path changes fail decode; following good decode succeeds.");
+
+promise_test(function(t) {
+  var img = new Image();
+  img.src = "/images/green.png";
+  var first_promise = img.decode();
+  img.src = "/non/existent/path.png";
+  var second_promise = img.decode();
+  assert_true(first_promise !== second_promise);
+  return Promise.all([
+    promise_rejects(t, "EncodingError", first_promise),
+    promise_rejects(t, "EncodingError", second_promise)
+  ]);
+}, "(src) Path changes fail decode; following bad decode fails.");
+
+promise_test(function() {
+  var img = new Image();
+  img.src = "/images/green.png";
+  var first_promise = img.decode();
+  img.src = "/images/green.png";
+  var second_promise = img.decode();
+  assert_true(first_promise !== second_promise);
+  return Promise.all([
+    first_promise,
+    second_promise
+  ]);
+}, "(src) Path changes to the same path succeed.");
+
+// srcset tests
+// -------------------
+promise_test(function(t) {
+  var img = new Image();
+  img.srcset = "/images/green.png 100w";
+  var promise = img.decode();
+  img.srcset = "/images/green.svg 100w";
+  return promise_rejects(t, "EncodingError", promise);
+}, "(srcset) Path changes fail decode.");
+
+promise_test(function(t) {
+  var img = new Image();
+  img.srcset = "/images/green.png 100w";
+  var first_promise = img.decode();
+  img.srcset = "/images/green.svg 100w";
+  var second_promise = img.decode();
+  assert_true(first_promise !== second_promise);
+  return Promise.all([
+    promise_rejects(t, "EncodingError", first_promise),
+    second_promise
+  ]);
+}, "(srcset) Path changes fail decode; following good decode succeeds.");
+
+promise_test(function(t) {
+  var img = new Image();
+  img.srcset = "/images/green.png 100w";
+  var first_promise = img.decode();
+  img.srcset = "/non/existent/path.png 100w";
+  var second_promise = img.decode();
+  assert_true(first_promise !== second_promise);
+  return Promise.all([
+    promise_rejects(t, "EncodingError", first_promise),
+    promise_rejects(t, "EncodingError", second_promise)
+  ]);
+}, "(srcset) Path changes fail decode; following bad decode fails.");
+
+promise_test(function() {
+  var img = new Image();
+  img.srcset = "/images/green.png 100w";
+  var first_promise = img.decode();
+  img.srcset = "/images/green.png 100w";
+  var second_promise = img.decode();
+  assert_true(first_promise !== second_promise);
+  return Promise.all([
+    first_promise,
+    second_promise
+  ]);
+}, "(srcset) Path changes to the same path succeed.");
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/image-decodes/image-decode.html b/third_party/WebKit/LayoutTests/external/wpt/image-decodes/image-decode.html
new file mode 100644
index 0000000..5b8c1b6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/image-decodes/image-decode.html
@@ -0,0 +1,112 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>img.decode()</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel=help href="">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+
+<script>
+"use strict";
+
+// src tests
+// -------------------
+promise_test(function() {
+  var img = new Image();
+  img.src = "/images/green.png";
+  return img.decode().then(function(arg) {
+    assert_equals(arg, undefined);
+  });
+}, "(src) PNG image decodes with undefined.");
+
+promise_test(function() {
+  var img = new Image();
+  img.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAA" +
+            "D91JpzAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4QUSEioKsyAgyw" +
+            "AAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAAWSURBVA" +
+            "jXY9y3bx8DAwPL58+fGRgYACktBRltLfebAAAAAElFTkSuQmCC";
+  return img.decode().then(function(arg) {
+    assert_equals(arg, undefined);
+  });
+}, "(src) PNG url image decodes with undefined.");
+
+promise_test(function() {
+  var img = new Image();
+  img.src = "/images/green.svg";
+  return img.decode().then(function(arg) {
+    assert_equals(arg, undefined);
+  });
+}, "(src) SVG image decodes with undefined.");
+
+promise_test(function(t) {
+  var img = new Image();
+  img.src = "/non/existent/path.png";
+  var promise = img.decode();
+  return promise_rejects(t, "EncodingError", promise);
+}, "(src) Non-existent path fails decode.");
+
+promise_test(function(t) {
+  var img = new Image();
+  img.src = "data:image/png;base64,iVBO00PDR0BADBEEF00KGg";
+  var promise = img.decode();
+  return promise_rejects(t, "EncodingError", promise);
+}, "(src) Corrupt image fails decode.");
+
+promise_test(function(t) {
+  var img = new Image();
+  var promise = img.decode();
+  return promise_rejects(t, "EncodingError", promise);
+}, "(src) Path-less image fails decode.");
+
+promise_test(function() {
+  var img = new Image();
+  img.src = "/images/green.png";
+  var first_promise = img.decode();
+  var second_promise = img.decode();
+  assert_true(first_promise !== second_promise);
+  return Promise.all([
+    first_promise,
+    second_promise
+  ]);
+}, "(src) Multiple decodes succeed.");
+
+// srcset tests
+// -------------------
+promise_test(function() {
+  var img = new Image();
+  img.srcset = "/images/green.png 100w";
+  return img.decode().then(function(arg) {
+    assert_equals(arg, undefined);
+  });
+}, "(srcset) PNG image decodes with undefined.");
+
+promise_test(function() {
+  var img = new Image();
+  img.srcset = "/images/green.svg 100w";
+  return img.decode().then(function(arg) {
+    assert_equals(arg, undefined);
+  });
+}, "(srcset) SVG image decodes with undefined.");
+
+promise_test(function(t) {
+  var img = new Image();
+  img.srcset = "/non/existent/path.png 100w";
+  var promise = img.decode();
+  return promise_rejects(t, "EncodingError", promise);
+}, "(srcset) Non-existent path fails decode.");
+
+promise_test(function() {
+  var img = new Image();
+  img.srcset = "/images/green.png 100w";
+  var first_promise = img.decode();
+  var second_promise = img.decode();
+  assert_true(first_promise !== second_promise);
+  return Promise.all([
+    first_promise,
+    second_promise
+  ]);
+}, "(srcset) Multiple decodes succeed.");
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/input-events/input-events-typing-data-manual.html b/third_party/WebKit/LayoutTests/external/wpt/input-events/input-events-typing-data-manual.html
new file mode 100644
index 0000000..2b4a809
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/input-events/input-events-typing-data-manual.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>InputEvent have data when typing on textarea and contenteditable</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<p>To manually run this test, please follow the steps below:<br/>
+1. Focus the first box and press key 'a' and then 'b'.<br/>
+2. Focus the second box and press key 'c' and then 'd'.<br/>
+<br/>
+If a "PASS" result appears the test passes, otherwise it fails</p>
+<textarea id='plain'></textarea>
+<div id='rich' style='border-style: solid;' contenteditable></div>
+<script>
+async_test(t => {
+    const expectedResult = [
+        'plain-beforeinput-a',
+        'plain-input-a',
+        'plain-beforeinput-b',
+        'plain-input-b',
+        'rich-beforeinput-c',
+        'rich-input-c',
+        'rich-beforeinput-d',
+        'rich-input-d',
+    ];
+    let eventCounter = 0;
+
+    for (const targetId of ['plain', 'rich']) {
+        for (const eventType of ['beforeinput', 'input']) {
+            document.getElementById(targetId).addEventListener(eventType, t.step_func(e => {
+                assert_equals(`${targetId}-${eventType}-${e.data}`, expectedResult[eventCounter]);
+                ++eventCounter;
+                if (eventCounter === expectedResult.length)
+                    t.done();
+            }));
+        }
+    }
+})
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/media-source/mediasource-duration.html b/third_party/WebKit/LayoutTests/external/wpt/media-source/mediasource-duration.html
index 4bc0fb2..a7760b66 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/media-source/mediasource-duration.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/media-source/mediasource-duration.html
@@ -44,7 +44,7 @@
                   test.waitForExpectedEvents(function()
                   {
                       assert_greater_than_equal(mediaElement.currentTime, seekTo, 'Playback time has reached seekTo');
-                      assert_false(mediaElement.seeking, 'mediaElement.seeking after seeked to seekTo');
+                      assert_false(mediaElement.seeking, 'mediaElement.seeking after sought to seekTo');
 
                       assert_false(sourceBuffer.updating, 'sourceBuffer.updating');
 
@@ -133,7 +133,7 @@
                                        'mediaElement duration increased by new append');
                   assert_equals(mediaSource.duration, mediaElement.duration,
                                 'mediaSource duration increased by new append');
-                  assert_false(mediaElement.seeking, 'mediaElement.seeking after seeked to truncatedDuration');
+                  assert_false(mediaElement.seeking, 'mediaElement.seeking after sought to truncatedDuration');
 
                   test.done();
               });
@@ -162,7 +162,7 @@
                                 'mediaElement truncatedDuration after seek to it');
                   assert_equals(mediaSource.duration, truncatedDuration,
                                 'mediaSource truncatedDuration after seek to it');
-                  assert_false(mediaElement.seeking, 'mediaElement.seeking after seeked to truncatedDuration');
+                  assert_false(mediaElement.seeking, 'mediaElement.seeking after sought to truncatedDuration');
 
                   test.done();
               });
diff --git a/third_party/WebKit/LayoutTests/external/wpt/media-source/mediasource-redundant-seek.html b/third_party/WebKit/LayoutTests/external/wpt/media-source/mediasource-redundant-seek.html
index 05eae97..ab11b25 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/media-source/mediasource-redundant-seek.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/media-source/mediasource-redundant-seek.html
@@ -49,7 +49,7 @@
 
                 test.waitForExpectedEvents(function()
                 {
-                    // No more seeking or seeked events should occur.
+                    // No more seeking or sought events should occur.
                     mediaElement.addEventListener('seeking', test.unreached_func("Unexpected event 'seeking'"));
                     mediaElement.addEventListener('seeked', test.unreached_func("Unexpected event 'seeked'"));
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/media-source/mediasource-seek-during-pending-seek.html b/third_party/WebKit/LayoutTests/external/wpt/media-source/mediasource-seek-during-pending-seek.html
index 60c5eec..bd8bcea 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/media-source/mediasource-seek-during-pending-seek.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/media-source/mediasource-seek-during-pending-seek.html
@@ -153,7 +153,7 @@
 
                   if (sourceBuffer.updating)
                   {
-                      // The event seeked was fired prior to the appendBuffer completing.
+                      // The event sought was fired prior to the appendBuffer completing.
                       test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
                       test.waitForExpectedEvents(function()
                       {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/pointerevents/pointerevent_pointerenter_does_not_bubble-manual.html b/third_party/WebKit/LayoutTests/external/wpt/pointerevents/pointerevent_pointerenter_does_not_bubble-manual.html
index 3f05833..c59741fe 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/pointerevents/pointerevent_pointerenter_does_not_bubble-manual.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/pointerevents/pointerevent_pointerenter_does_not_bubble-manual.html
@@ -45,7 +45,7 @@
                 on_event(parent0, "pointerenter", function (event) {
                     detected_pointertypes[event.pointerType] = true;
                     test_pointerEvent.step(function () {
-                        assert_equals(event.target.id, "parent0", "Recieved " + event.type + " in parent for " + event.target.id);
+                        assert_equals(event.target.id, "parent0", "Received " + event.type + " in parent for " + event.target.id);
                     });
                 });
             }
diff --git a/third_party/WebKit/LayoutTests/external/wpt/pointerevents/pointerevent_pointerleave_does_not_bubble-manual.html b/third_party/WebKit/LayoutTests/external/wpt/pointerevents/pointerevent_pointerleave_does_not_bubble-manual.html
index c0e551cd..e1c55db 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/pointerevents/pointerevent_pointerleave_does_not_bubble-manual.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/pointerevents/pointerevent_pointerleave_does_not_bubble-manual.html
@@ -34,7 +34,7 @@
 
                 on_event(parent0, "pointerleave", function (event) {
                     test_pointerEvent.step(function () {
-                        assert_equals(event.target.id, "parent0", "Recieved " + event.type + " in parent for " + event.target.id);
+                        assert_equals(event.target.id, "parent0", "Received " + event.type + " in parent for " + event.target.id);
                     });
                     test_pointerEvent.done(); // complete test
                 });
diff --git a/third_party/WebKit/LayoutTests/external/wpt/pointerevents/pointerevent_releasepointercapture_events_to_original_target-manual.html b/third_party/WebKit/LayoutTests/external/wpt/pointerevents/pointerevent_releasepointercapture_events_to_original_target-manual.html
index 89f3d839..2e5494b 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/pointerevents/pointerevent_releasepointercapture_events_to_original_target-manual.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/pointerevents/pointerevent_releasepointercapture_events_to_original_target-manual.html
@@ -67,7 +67,7 @@
                         // if any other events are received after releaseCapture, then the test fails
                         test(function () {
                             assert_unreached(event.target.id + "-" + event.type + " should be handled by target element handler");
-                        }, expectedPointerType + " No other events should be recieved by capturing node after release");
+                        }, expectedPointerType + " No other events should be received by capturing node after release");
                     }
                 }
             }
@@ -78,7 +78,7 @@
                 if (f_gotPointerCapture) {
                     if(event.type != "pointerout" && event.type != "pointerleave") {
                         test(function () {
-                            assert_unreached("The Target element should not have received any events while capture is active. Event recieved:" + event.type + ".  ");
+                            assert_unreached("The Target element should not have received any events while capture is active. Event received:" + event.type + ".  ");
                         }, expectedPointerType + " The target element should not receive any events while capture is active");
                     }
                 }
diff --git a/third_party/WebKit/LayoutTests/external/wpt/pointerlock/pointerlock_fullscreen-manual.html b/third_party/WebKit/LayoutTests/external/wpt/pointerlock/pointerlock_fullscreen-manual.html
index 7ce91ad..a78762dd 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/pointerlock/pointerlock_fullscreen-manual.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/pointerlock/pointerlock_fullscreen-manual.html
@@ -96,7 +96,7 @@
                 logStatus();
 
                 scriptExitFullscreenTest.step(function() {
-                    assert_true(FullscreenElement() === null, "fullscreen is sucessfully exited");
+                    assert_true(FullscreenElement() === null, "fullscreen is successfully exited");
                     assert_true(document.pointerLockElement === test_element, "pointer is still locked at the target element");
                 });
                 scriptExitFullscreenTest.done();
@@ -114,8 +114,8 @@
                 if(gestureExit_fs) {
                 // second test, fullscreen and pointer lock both exited
                     gestureExitFullscreenTest.step(function() {
-                        assert_true(document.pointerLockElement === null, "pointer is sucessfully exited");
-                        assert_true(FullscreenElement() === null, "fullscreen is sucessfully exited");
+                        assert_true(document.pointerLockElement === null, "pointer is successfully exited");
+                        assert_true(FullscreenElement() === null, "fullscreen is successfully exited");
                 });
                 gestureExitFullscreenTest.done();
                 }
@@ -132,8 +132,8 @@
             if(gestureExit_pl) {
             // second test, fullscreen and pointer lock both exited
                 gestureExitFullscreenTest.step(function() {
-                    assert_true(document.pointerLockElement === null, "pointer is sucessfully exited");
-                    assert_true(FullscreenElement() === null, "fullscreen is sucessfully exited");
+                    assert_true(document.pointerLockElement === null, "pointer is successfully exited");
+                    assert_true(FullscreenElement() === null, "fullscreen is successfully exited");
                 });
 
             gestureExitFullscreenTest.done();
diff --git a/third_party/WebKit/LayoutTests/external/wpt/referrer-policy/css-integration/README.md b/third_party/WebKit/LayoutTests/external/wpt/referrer-policy/css-integration/README.md
index 2edb24f..b1a2f9c 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/referrer-policy/css-integration/README.md
+++ b/third_party/WebKit/LayoutTests/external/wpt/referrer-policy/css-integration/README.md
@@ -1,4 +1,4 @@
-These tests exercise differnt ways to load an image, generated via
+These tests exercise different ways to load an image, generated via
 ```/referrer-policy/generic/subresource/image.py?id=<UUID>``` and later
 verify the headers used to request that image.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/resource-timing/resources/TAOResponse.py b/third_party/WebKit/LayoutTests/external/wpt/resource-timing/resources/TAOResponse.py
index cc8fa5f..325a684a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/resource-timing/resources/TAOResponse.py
+++ b/third_party/WebKit/LayoutTests/external/wpt/resource-timing/resources/TAOResponse.py
@@ -17,18 +17,18 @@
     # case-sensitive match for origin, pass
         response.headers.set('Timing-Allow-Origin', origin)
     elif tao == 'space':
-    # space seperated list of origin and wildcard, fail
+    # space separated list of origin and wildcard, fail
         response.headers.set('Timing-Allow-Origin', (origin + ' *'))
     elif tao == 'multi':
-    # more than one TAO values, seperated by common, pass
+    # more than one TAO values, separated by common, pass
         response.headers.set('Timing-Allow-Origin', origin)
         response.headers.append('Timing-Allow-Origin', '*')
     elif tao == 'match_origin':
-    # contains a match of origin, seperated by common, pass
+    # contains a match of origin, separated by common, pass
         response.headers.set('Timing-Allow-Origin', origin)
         response.headers.append('Timing-Allow-Origin', "fake")
     elif tao == 'match_wildcard':
-    # contains a wildcard, seperated by common, pass
+    # contains a wildcard, separated by common, pass
         response.headers.set('Timing-Allow-Origin', "fake")
         response.headers.append('Timing-Allow-Origin', '*')
     elif tao == 'uppercase':
diff --git a/third_party/WebKit/LayoutTests/external/wpt/resources/testharness.js b/third_party/WebKit/LayoutTests/external/wpt/resources/testharness.js
index 73913d6..a0ec94d 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/resources/testharness.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/resources/testharness.js
@@ -591,7 +591,7 @@
 
         /**
          * Returns a Promise that will resolve after the specified event or
-         * series of events has occured.
+         * series of events has occurred.
          */
         this.wait_for = function(types) {
             if (waitingFor) {
@@ -971,7 +971,7 @@
     function assert_approx_equals(actual, expected, epsilon, description)
     {
         /*
-         * Test if two primitive numbers are equal withing +/- epsilon
+         * Test if two primitive numbers are equal within +/- epsilon
          */
         assert(typeof actual === "number",
                "assert_approx_equals", description,
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/fetch-header-visibility.https.html b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/fetch-header-visibility.https.html
index 1ceb164..04e1677b 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/fetch-header-visibility.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/fetch-header-visibility.https.html
@@ -22,7 +22,7 @@
         frame.src = scope;
         document.body.appendChild(frame);
 
-        // Resolve a promise when we recieve 2 success messages
+        // Resolve a promise when we receive 2 success messages
         return new Promise(function(resolve, reject) {
           var remaining = 4;
           function onMessage(e) {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/fetch-request-redirect.https.html b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/fetch-request-redirect.https.html
index 18bfa61e..eb148550 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/fetch-request-redirect.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/fetch-request-redirect.https.html
@@ -182,7 +182,7 @@
         });
   }, 'Verify redirect mode of Fetch API and ServiceWorker FetchEvent.');
 
-// test for reponse.redirected
+// test for response.redirected
 promise_test(function(t) {
     var SCOPE = 'resources/fetch-request-redirect-iframe.html';
     var SCRIPT = 'resources/fetch-rewrite-worker.js';
@@ -276,7 +276,7 @@
         });
   }, 'Verify redirected of Response(Fetch API) and ServiceWorker FetchEvent.');
 
-// test for reponse.redirected after cached
+// test for response.redirected after cached
 promise_test(function(t) {
     var SCOPE = 'resources/fetch-request-redirect-iframe.html';
     var SCRIPT = 'resources/fetch-rewrite-worker.js';
diff --git a/third_party/WebKit/LayoutTests/external/wpt/shadow-dom/untriaged/events/retargeting-focus-events/test-001.html b/third_party/WebKit/LayoutTests/external/wpt/shadow-dom/untriaged/events/retargeting-focus-events/test-001.html
index 296346b..66e8d9c 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/shadow-dom/untriaged/events/retargeting-focus-events/test-001.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/shadow-dom/untriaged/events/retargeting-focus-events/test-001.html
@@ -106,7 +106,7 @@
 }));
 
 
-//gaining and loosing focus elements are in the same tree.
+//gaining and losing focus elements are in the same tree.
 //DOMFocusIn event should be stopped at shadow boundary
 var A_05_03_01_T03 = async_test('A_05_03_01_T03');
 
@@ -147,7 +147,7 @@
 
 
 
-//gaining and loosing focus elements are in the same tree.
+//gaining and losing focus elements are in the same tree.
 //DOMFocusOut event should be stopped at shadow boundary
 var A_05_03_01_T04 = async_test('A_05_03_01_T04');
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/shadow-dom/untriaged/styles/test-008.html b/third_party/WebKit/LayoutTests/external/wpt/shadow-dom/untriaged/styles/test-008.html
index b84ca4d..af76fa9c 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/shadow-dom/untriaged/styles/test-008.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/shadow-dom/untriaged/styles/test-008.html
@@ -48,7 +48,7 @@
     host.setAttribute('style', 'font-size:20px');
 
     assert_true(s.querySelector('#spn2').offsetHeight > oldHeight,
-        'Shadow host style must be aplied to the shadow root children');
+        'Shadow host style must be applied to the shadow root children');
 
 }), 'A_06_00_09_T01');
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/uievents/resources/eventrecorder.js b/third_party/WebKit/LayoutTests/external/wpt/uievents/resources/eventrecorder.js
index 649930b..5442381a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/uievents/resources/eventrecorder.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/uievents/resources/eventrecorder.js
@@ -70,7 +70,7 @@
 //    //<recorded property names with their values for all enumerable properties of the event object instance>
 // };
 // * EventRecordDetails
-//   * For records with 'sequentialOccurrences' > 1, only the first occurence is recorded (subsequent event details are dropped).
+//   * For records with 'sequentialOccurrences' > 1, only the first occurrence is recorded (subsequent event details are dropped).
 //   * Object reference values (e.g., event.target, event.currentTarget, etc.) are replaced with their mapped 'targetTestID' string.
 //     If no 'targetTestID' string mapping is available for a particular object, the value 'UNKNOWN_OBJECT' is returned.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/user-timing/measure.html b/third_party/WebKit/LayoutTests/external/wpt/user-timing/measure.html
index 4175dbb4..1916813 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/user-timing/measure.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/user-timing/measure.html
@@ -76,7 +76,7 @@
 
         function onload_test()
         {
-            // test for existance of User Timing and Performance Timeline interface
+            // test for existence of User Timing and Performance Timeline interface
             if (!has_required_interfaces())
             {
                 test_true(false,
diff --git a/third_party/WebKit/LayoutTests/external/wpt/user-timing/measure_navigation_timing.html b/third_party/WebKit/LayoutTests/external/wpt/user-timing/measure_navigation_timing.html
index 93b6dc2..abd3f629 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/user-timing/measure_navigation_timing.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/user-timing/measure_navigation_timing.html
@@ -73,7 +73,7 @@
 
         function onload_test()
         {
-            // test for existance of User Timing and Performance Timeline interface
+            // test for existence of User Timing and Performance Timeline interface
             if (!has_required_interfaces())
             {
                 test_true(false,
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/mediaElementAudioSourceToScriptProcessorTest.html b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/mediaElementAudioSourceToScriptProcessorTest.html
index ba6eec6..7e1514a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/mediaElementAudioSourceToScriptProcessorTest.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/mediaElementAudioSourceToScriptProcessorTest.html
@@ -7,7 +7,7 @@
 array, and after the playback has stopped, the contents are compared
 to those of a loaded AudioBuffer with the same source.
 
-Somewhat similiar to a test from Mozilla:
+Somewhat similar to a test from Mozilla:
 (http://dxr.mozilla.org/mozilla-central/source/content/media/webaudio/test/test_mediaElementAudioSourceNode.html?force=1)
 -->
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/workers/constructors/SharedWorker/same-origin.html b/third_party/WebKit/LayoutTests/external/wpt/workers/constructors/SharedWorker/same-origin.html
index 78d53164..87a3cc89 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/workers/constructors/SharedWorker/same-origin.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/workers/constructors/SharedWorker/same-origin.html
@@ -9,7 +9,7 @@
 <div id="log"></div>
 <script>
 // Needed to prevent a race condition if a worker throws an exception that may or may
-// not propogate to the window before the tests finish
+// not propagate to the window before the tests finish
 setup({allow_uncaught_exception: true});
 
 function testSharedWorkerHelper(t, script) {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/workers/constructors/Worker/same-origin.html b/third_party/WebKit/LayoutTests/external/wpt/workers/constructors/Worker/same-origin.html
index bbc4382..7fbf6d34 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/workers/constructors/Worker/same-origin.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/workers/constructors/Worker/same-origin.html
@@ -7,7 +7,7 @@
 <div id="log"></div>
 <script>
 // Needed to prevent a race condition if a worker throws an exception that may or may
-// not propogate to the window before the tests finish
+// not propagate to the window before the tests finish
 setup({allow_uncaught_exception: true});
 
 function testSharedWorkerHelper(t, script) {
diff --git a/third_party/WebKit/LayoutTests/external/wpt_automation/input-events/input-events-typing-data-manual-automation.js b/third_party/WebKit/LayoutTests/external/wpt_automation/input-events/input-events-typing-data-manual-automation.js
new file mode 100644
index 0000000..58474a47
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt_automation/input-events/input-events-typing-data-manual-automation.js
@@ -0,0 +1,11 @@
+importAutomationScript('/input-events/inputevent_common_input.js');
+
+function inject_input() {
+  return focusAndKeyDown('#plain', 'a').then(() => {
+    return keyDown('b');
+  }).then(() => {
+    return focusAndKeyDown('#rich', 'c');
+  }).then(() => {
+    return keyDown('d');
+  });
+}
diff --git a/third_party/WebKit/LayoutTests/external/wpt_automation/input-events/inputevent_common_input.js b/third_party/WebKit/LayoutTests/external/wpt_automation/input-events/inputevent_common_input.js
new file mode 100644
index 0000000..f846acb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt_automation/input-events/inputevent_common_input.js
@@ -0,0 +1,22 @@
+// Returns a Promise for future conversion into WebDriver-backed API.
+function keyDown(key, modifiers) {
+  return new Promise(function(resolve, reject) {
+    if (window.eventSender) {
+      eventSender.keyDown(key, modifiers);
+      resolve();
+    } else {
+      reject();
+    }
+  });
+}
+
+function focusAndKeyDown(selector, key, modifiers) {
+  document.querySelector(selector).focus();
+  return keyDown(key, modifiers);
+}
+
+{
+  const inputevent_automation = async_test("InputEvent Automation");
+  // Defined in every test and should return a promise that gets resolved when input is finished.
+  inject_input().then(inputevent_automation.step_func_done());
+}
diff --git a/third_party/WebKit/LayoutTests/fast/block/block-with-inline-replaced-child-expected.html b/third_party/WebKit/LayoutTests/fast/block/block-with-inline-replaced-child-expected.html
index 1647de4..be24e01a 100644
--- a/third_party/WebKit/LayoutTests/fast/block/block-with-inline-replaced-child-expected.html
+++ b/third_party/WebKit/LayoutTests/fast/block/block-with-inline-replaced-child-expected.html
@@ -2,7 +2,7 @@
 <html>
 <body>
 <div>Test for Bugzilla bug:<a href="https://bugs.webkit.org/show_bug.cgi?id=84624"> 84624</a> LayoutBlockFlow incorrectly calculates pref width when a replaced object follows a LayoutInline with width.</div>
-<div>This test verifies that the containing block grows in order to accomodate it's replaced child (image).</div>
+<div>This test verifies that the containing block grows in order to accommodate it's replaced child (image).</div>
 <div style="width: 80px; border: 1px solid black;">
     <span style="padding-left: 30px;"><img width=50 height=50 src="resources/50x50.gif"/></span>
 </div>
diff --git a/third_party/WebKit/LayoutTests/fast/block/block-with-inline-replaced-child.html b/third_party/WebKit/LayoutTests/fast/block/block-with-inline-replaced-child.html
index 8b71542..0f53375 100644
--- a/third_party/WebKit/LayoutTests/fast/block/block-with-inline-replaced-child.html
+++ b/third_party/WebKit/LayoutTests/fast/block/block-with-inline-replaced-child.html
@@ -2,7 +2,7 @@
 <html>
 <body>
 <div>Test for Bugzilla bug:<a href="https://bugs.webkit.org/show_bug.cgi?id=84624"> 84624</a> LayoutBlockFlow incorrectly calculates pref width when a replaced object follows a LayoutInline with width.</div>
-<div>This test verifies that the containing block grows in order to accomodate it's replaced child (image).</div>
+<div>This test verifies that the containing block grows in order to accommodate it's replaced child (image).</div>
 <div style="width: 50px">
     <span style="float: left; border: 1px solid black;">
         <span style="padding-left: 30px;"><img width=50 height=50 src="resources/50x50.gif"/></span>
diff --git a/third_party/WebKit/LayoutTests/fast/block/positioning/positioned-child-inside-relative-positioned-anonymous-block-expected.txt b/third_party/WebKit/LayoutTests/fast/block/positioning/positioned-child-inside-relative-positioned-anonymous-block-expected.txt
index 30af33e..b3fa3dd 100644
--- a/third_party/WebKit/LayoutTests/fast/block/positioning/positioned-child-inside-relative-positioned-anonymous-block-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/block/positioning/positioned-child-inside-relative-positioned-anonymous-block-expected.txt
@@ -1,4 +1,4 @@
-crbug.com/548017: A positioned element inside a relatively positioned inline should use the width of the inline, rather than the anonymous block created to accomodate block-flow parents, when determining its own width. There should be a green square below
+crbug.com/548017: A positioned element inside a relatively positioned inline should use the width of the inline, rather than the anonymous block created to accommodate block-flow parents, when determining its own width. There should be a green square below
 
  PASS
 
diff --git a/third_party/WebKit/LayoutTests/fast/block/positioning/positioned-child-inside-relative-positioned-anonymous-block.html b/third_party/WebKit/LayoutTests/fast/block/positioning/positioned-child-inside-relative-positioned-anonymous-block.html
index 35d76f49..88b972a 100644
--- a/third_party/WebKit/LayoutTests/fast/block/positioning/positioned-child-inside-relative-positioned-anonymous-block.html
+++ b/third_party/WebKit/LayoutTests/fast/block/positioning/positioned-child-inside-relative-positioned-anonymous-block.html
@@ -15,7 +15,7 @@
     background-color: green;
 }
 </style>
-<p> crbug.com/548017: A positioned element inside a relatively positioned inline should use the width of the inline, rather than the anonymous block created to accomodate block-flow parents, when determining its own width. There should be a green square below</p>
+<p> crbug.com/548017: A positioned element inside a relatively positioned inline should use the width of the inline, rather than the anonymous block created to accommodate block-flow parents, when determining its own width. There should be a green square below</p>
 <div id="inline-container">
     <div>
         <div id="abspos" data-expected-width=50><div id="square"></div><div id="square"></div></div>
diff --git a/third_party/WebKit/LayoutTests/fast/box-sizing/percentage-height.html b/third_party/WebKit/LayoutTests/fast/box-sizing/percentage-height.html
index 51ded9e2..b19f465 100644
--- a/third_party/WebKit/LayoutTests/fast/box-sizing/percentage-height.html
+++ b/third_party/WebKit/LayoutTests/fast/box-sizing/percentage-height.html
@@ -109,7 +109,7 @@
 }
 
 *|*::-moz-button-content {
-    postion: relative;
+    position: relative;
     margin: 0;
     padding: 0;
     text-align: left;
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-grow-tracks-to-their-max-expected.txt b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-grow-tracks-to-their-max-expected.txt
index b0bcfb7..e7a57087 100644
--- a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-grow-tracks-to-their-max-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-grow-tracks-to-their-max-expected.txt
@@ -1,4 +1,4 @@
-Check that tracks are not shrinked if the available space is indefinite.
+Check that tracks are not shrunk if the available space is indefinite.
 PASS window.getComputedStyle(gridContentSizedColumn, '').getPropertyValue('grid-template-columns') is "50px"
 PASS window.getComputedStyle(gridContentSizedColumn, '').getPropertyValue('grid-template-rows') is "10px"
 PASS window.getComputedStyle(gridContentSizedRow, '').getPropertyValue('grid-template-columns') is "40px"
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-grow-tracks-to-their-max.html b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-grow-tracks-to-their-max.html
index 5caa68d..e3ebf64 100644
--- a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-grow-tracks-to-their-max.html
+++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-grow-tracks-to-their-max.html
@@ -69,7 +69,7 @@
 
 
 <script>
-debug("Check that tracks are not shrinked if the available space is indefinite.");
+debug("Check that tracks are not shrunk if the available space is indefinite.");
 testGridDefinitionsValues(document.getElementById("gridContentSizedColumn"), "50px", "10px");
 testGridDefinitionsValues(document.getElementById("gridContentSizedRow"), "40px", "20px");
 
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-auto-margins-alignment-expected.txt b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-auto-margins-alignment-expected.txt
index 0857c0d9..194372c 100644
--- a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-auto-margins-alignment-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-auto-margins-alignment-expected.txt
@@ -1,4 +1,4 @@
-This test checks that aling-self and justify-self properties are not applied when there is auto-margin in the correponding axis. Instead, auto-margin alignment should be applied.
+This test checks that aling-self and justify-self properties are not applied when there is auto-margin in the corresponding axis. Instead, auto-margin alignment should be applied.
 
 Direction: LTR | Self Alignment: center | fixed size items | 1 auto-margin
 
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-auto-margins-alignment-vertical-lr-expected.txt b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-auto-margins-alignment-vertical-lr-expected.txt
index 24e90e1f..d996143 100644
--- a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-auto-margins-alignment-vertical-lr-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-auto-margins-alignment-vertical-lr-expected.txt
@@ -1,4 +1,4 @@
-This test checks on a vertical-lr grid that aling-self and justify-self properties are not applied when there is auto-margin in the correponding axis. Instead, auto-margin alignment should be applied.
+This test checks on a vertical-lr grid that aling-self and justify-self properties are not applied when there is auto-margin in the corresponding axis. Instead, auto-margin alignment should be applied.
 
 Direction: LTR | Self Alignment: center | fixed size items | 1 auto-margin
 
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-auto-margins-alignment-vertical-lr.html b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-auto-margins-alignment-vertical-lr.html
index 14aadaa..84d293f 100644
--- a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-auto-margins-alignment-vertical-lr.html
+++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-auto-margins-alignment-vertical-lr.html
@@ -30,7 +30,7 @@
 </head>
 <body onload="checkLayout('.grid')">
 
-<p>This test checks on a vertical-lr grid that aling-self and justify-self properties are not applied when there is auto-margin in the correponding axis. Instead, auto-margin alignment should be applied.</p>
+<p>This test checks on a vertical-lr grid that aling-self and justify-self properties are not applied when there is auto-margin in the corresponding axis. Instead, auto-margin alignment should be applied.</p>
 
 <p>Direction: LTR | Self Alignment: center | fixed size items | 1 auto-margin</p>
 <div style="position: relative">
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-auto-margins-alignment-vertical-rl-expected.txt b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-auto-margins-alignment-vertical-rl-expected.txt
index da55e07..59be6130 100644
--- a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-auto-margins-alignment-vertical-rl-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-auto-margins-alignment-vertical-rl-expected.txt
@@ -1,4 +1,4 @@
-This test checks on a vertical-rl grid that aling-self and justify-self properties are not applied when there is auto-margin in the correponding axis. Instead, auto-margin alignment should be applied.
+This test checks on a vertical-rl grid that aling-self and justify-self properties are not applied when there is auto-margin in the corresponding axis. Instead, auto-margin alignment should be applied.
 
 Direction: LTR | Self Alignment: center | fixed size items | 1 auto-margin
 
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-auto-margins-alignment-vertical-rl.html b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-auto-margins-alignment-vertical-rl.html
index 53fc0e6..b4a5044f 100644
--- a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-auto-margins-alignment-vertical-rl.html
+++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-auto-margins-alignment-vertical-rl.html
@@ -30,7 +30,7 @@
 </head>
 <body onload="checkLayout('.grid')">
 
-<p>This test checks on a vertical-rl grid that aling-self and justify-self properties are not applied when there is auto-margin in the correponding axis. Instead, auto-margin alignment should be applied.</p>
+<p>This test checks on a vertical-rl grid that aling-self and justify-self properties are not applied when there is auto-margin in the corresponding axis. Instead, auto-margin alignment should be applied.</p>
 
 <p>Direction: LTR | Self Alignment: center | fixed size items | 1 auto-margin</p>
 <div style="position: relative">
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-auto-margins-alignment.html b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-auto-margins-alignment.html
index 2a45f58..10f4d9c 100644
--- a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-auto-margins-alignment.html
+++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-auto-margins-alignment.html
@@ -30,7 +30,7 @@
 </head>
 <body onload="checkLayout('.grid')">
 
-<p>This test checks that aling-self and justify-self properties are not applied when there is auto-margin in the correponding axis. Instead, auto-margin alignment should be applied.</p>
+<p>This test checks that aling-self and justify-self properties are not applied when there is auto-margin in the corresponding axis. Instead, auto-margin alignment should be applied.</p>
 
 <p>Direction: LTR | Self Alignment: center | fixed size items | 1 auto-margin</p>
 <div style="position: relative">
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/mozilla/grid-repeat-auto-fill-fit-001-expected.html b/third_party/WebKit/LayoutTests/fast/css-grid-layout/mozilla/grid-repeat-auto-fill-fit-001-expected.html
index 58e80a30..9067145 100644
--- a/third_party/WebKit/LayoutTests/fast/css-grid-layout/mozilla/grid-repeat-auto-fill-fit-001-expected.html
+++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/mozilla/grid-repeat-auto-fill-fit-001-expected.html
@@ -72,7 +72,7 @@
 .r1.c1 { grid-template-columns: [a] repeat(1, [b] 20px [c]) [d];}
 .r1.c2 { grid-template-columns: [a] repeat(2, [b] 20px [c]) [d]; }
 .r1.c4 { grid-template-columns: [a] repeat(4, [b] 20px [c]) [d]; }
-/* The repeat count was 18 in the original test. We had to reduce it to accomodate fit and fit tests
+/* The repeat count was 18 in the original test. We had to reduce it to accommodate fit and fit tests
    in a viewport with no scroll. */
 .r1.c18 { grid-template-columns: [a] repeat(17, [b] 20px [c]) [d]; }
 
@@ -81,7 +81,7 @@
 .r2.c1 { grid-template-columns: [a] repeat(1, [b] 20px [c]) [d] 30px [e]; }
 .r2.c2 { grid-template-columns: [a] repeat(2, [b] 20px [c]) [d] 30px [e]; }
 
-/* The repeat count was 15 in the original test. We had to reduce it to accomodate fit and fit tests
+/* The repeat count was 15 in the original test. We had to reduce it to accommodate fit and fit tests
    in a viewport with no scroll. */
 .r3.c15 { grid-template-columns: [a] repeat(14, [b] 20px [c]) [d] 30px [e] 30px [f]; }
 .r3.c0 { grid-template-columns: [a d] 30px [e] 30px [f]; }
diff --git a/third_party/WebKit/LayoutTests/fast/css/font-face-cache-version.html b/third_party/WebKit/LayoutTests/fast/css/font-face-cache-version.html
index c23d9ad..e5eddb7d 100644
--- a/third_party/WebKit/LayoutTests/fast/css/font-face-cache-version.html
+++ b/third_party/WebKit/LayoutTests/fast/css/font-face-cache-version.html
@@ -15,7 +15,7 @@
       });
     }
   });
-}, 'Cached font from differnt document should not be used');
+}, 'Cached font from different document should not be used');
 
 </script>
 <iframe id='frame' src='resources/font-face-cache-version-frame1.html'></iframe>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/viewport/viewport-scrollbars-cause-resize.html b/third_party/WebKit/LayoutTests/fast/dom/viewport/viewport-scrollbars-cause-resize.html
new file mode 100644
index 0000000..f0bf3ce
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/dom/viewport/viewport-scrollbars-cause-resize.html
@@ -0,0 +1,39 @@
+<!doctype html>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<h1>Viewport: Scrollbars Cause Resize</h1>
+<h4>Test Description: This test checks that the appearance of classic scrollbars will cause a resize event to be fired at window.view.</h4>
+<script>
+    document.documentElement.style.overflow = "hidden";
+    var initialWidth = view.width;
+    var initialHeight = view.height;
+
+    test(function() {
+          assert_equals(window.view.width, window.innerWidth);
+          assert_equals(window.view.height, window.innerHeight);
+        }, "view size initially matches window size");
+
+
+    var t = async_test("Resize event was fired at window.view");
+    var viewResized = false;
+    window.view.addEventListener('resize', function() {
+        viewResized = true;
+    });
+
+    requestAnimationFrame(t.step_func_done(function() {
+        assert_equals(viewResized, true);
+    }));
+
+    document.documentElement.style.overflow = "";
+    document.body.style.width = "10000px";
+    document.body.style.height = "10000px";
+
+    test(function() {
+          assert_equals(window.view.width, initialWidth - 15);
+          assert_equals(window.view.height, initialHeight - 15);
+        }, "view size reflects appearance of classic scrollbars");
+
+
+    document.body.style.width = "";
+    document.body.style.height = "";
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/events/crash-on-querying-event-path.html b/third_party/WebKit/LayoutTests/fast/events/crash-on-querying-event-path.html
index 8ffab27..9598291 100644
--- a/third_party/WebKit/LayoutTests/fast/events/crash-on-querying-event-path.html
+++ b/third_party/WebKit/LayoutTests/fast/events/crash-on-querying-event-path.html
@@ -25,7 +25,7 @@
     // The test is somewhat flaky, in that the test may pass as correct
     // despite the bug being the code. The exact conditions
     // are unclear, but 1, asan helps detect the crash and 2, the
-    // preceeding gc()s increase the likelihood of it occurring.
+    // preceding gc()s increase the likelihood of it occurring.
     gc();
     gc();
     gc();
diff --git a/third_party/WebKit/LayoutTests/fast/events/dblclick-addEventListener.html b/third_party/WebKit/LayoutTests/fast/events/dblclick-addEventListener.html
index 49e36f8..fe19d57d 100644
--- a/third_party/WebKit/LayoutTests/fast/events/dblclick-addEventListener.html
+++ b/third_party/WebKit/LayoutTests/fast/events/dblclick-addEventListener.html
@@ -38,7 +38,7 @@
 	</script>
 </head>
 <body>
-<div id="click_area" class="testarea">FAILURE, no dblclick recieved</div>
+<div id="click_area" class="testarea">FAILURE, no dblclick received</div>
 <br>
 <p>Double-click above to test.</p>
 </body>
diff --git a/third_party/WebKit/LayoutTests/fast/events/document-elementFromPoint.html b/third_party/WebKit/LayoutTests/fast/events/document-elementFromPoint.html
index 4813b37a..288d327 100644
--- a/third_party/WebKit/LayoutTests/fast/events/document-elementFromPoint.html
+++ b/third_party/WebKit/LayoutTests/fast/events/document-elementFromPoint.html
@@ -133,7 +133,7 @@
 <body>
     
 <!--
-  This test is modeled after <LayoutTests/fast/events/offsetX-offsetY.html>,
+  This test is modelled after <LayoutTests/fast/events/offsetX-offsetY.html>,
   but it is designed to not depend on inline text content to position the
   targets on which we click.
 -->
diff --git a/third_party/WebKit/LayoutTests/fast/events/middleClickAutoscroll-nested-divs.html b/third_party/WebKit/LayoutTests/fast/events/middleClickAutoscroll-nested-divs.html
index 56f90e2..f1b882e 100644
--- a/third_party/WebKit/LayoutTests/fast/events/middleClickAutoscroll-nested-divs.html
+++ b/third_party/WebKit/LayoutTests/fast/events/middleClickAutoscroll-nested-divs.html
@@ -26,7 +26,7 @@
 <div id="container">
 <p id="description"></p>
 Test for <a href="https://bugs.webkit.org/show_bug.cgi?id=28023">bug 28023</a> This tests that pan scrolling
-propogates correctly up the DOM tree. On success, our scroll offset should be non-zero.
+propagates correctly up the DOM tree. On success, our scroll offset should be non-zero.
 <div id="scrollable">
     <div style="height:200px; position:relative;">
         <div style="height:150px; border:1px blue solid; overflow:auto;">
diff --git a/third_party/WebKit/LayoutTests/fast/events/mouse-cursor-change.html b/third_party/WebKit/LayoutTests/fast/events/mouse-cursor-change.html
index e7e40ba..55d6a16 100644
--- a/third_party/WebKit/LayoutTests/fast/events/mouse-cursor-change.html
+++ b/third_party/WebKit/LayoutTests/fast/events/mouse-cursor-change.html
@@ -14,7 +14,7 @@
 <br/>
 <div id="console"></div>
 <script>
-// This appears to be just to accomodate style update (cursor is updated immediately on mouse events).
+// This appears to be just to accommodate style update (cursor is updated immediately on mouse events).
 // TODO(rbyers): replace with updateAfterDisplay or requestAnimationFrame
 var CURSOR_UPDATE_DELAY = 50;
 
diff --git a/third_party/WebKit/LayoutTests/fast/events/mouse-cursor-no-mousemove.html b/third_party/WebKit/LayoutTests/fast/events/mouse-cursor-no-mousemove.html
index 46b482b..3dfe3ad 100644
--- a/third_party/WebKit/LayoutTests/fast/events/mouse-cursor-no-mousemove.html
+++ b/third_party/WebKit/LayoutTests/fast/events/mouse-cursor-no-mousemove.html
@@ -14,7 +14,7 @@
 <br/>
 <div id="console"></div>
 <script>
-// This appears to be just to accomodate style update (cursor is updated immediately on mouse events).
+// This appears to be just to accommodate style update (cursor is updated immediately on mouse events).
 // TODO(rbyers): replace with updateAfterDisplay or requestAnimationFrame
 var CURSOR_UPDATE_DELAY = 50;
 
diff --git a/third_party/WebKit/LayoutTests/fast/events/mouseclick-target-and-positioning-expected.txt b/third_party/WebKit/LayoutTests/fast/events/mouseclick-target-and-positioning-expected.txt
index 18bd682e..e0601480 100644
--- a/third_party/WebKit/LayoutTests/fast/events/mouseclick-target-and-positioning-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/events/mouseclick-target-and-positioning-expected.txt
@@ -1,4 +1,4 @@
-This page tests whether a click event propogates with the correct target and positioning. See rdar://problem/4477126.
+This page tests whether a click event propagates with the correct target and positioning. See rdar://problem/4477126.
 
 click inside the red box:[]
 PASS: event target should be [object HTMLSpanElement] and is
diff --git a/third_party/WebKit/LayoutTests/fast/events/mouseclick-target-and-positioning.html b/third_party/WebKit/LayoutTests/fast/events/mouseclick-target-and-positioning.html
index c4ad9f2d..4b7cc85 100644
--- a/third_party/WebKit/LayoutTests/fast/events/mouseclick-target-and-positioning.html
+++ b/third_party/WebKit/LayoutTests/fast/events/mouseclick-target-and-positioning.html
@@ -82,7 +82,7 @@
 </script>
 </head>
 <body onload="test();">
-<p>This page tests whether a click event propogates with the correct target and positioning.
+<p>This page tests whether a click event propagates with the correct target and positioning.
 See <a href="rdar://problem/4477126">rdar://problem/4477126</a>.
 </p>
 <hr>
diff --git a/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-node-remove-expected.txt b/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-node-remove-expected.txt
index 9597f3c..dd76801 100644
--- a/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-node-remove-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-node-remove-expected.txt
@@ -1,4 +1,4 @@
-Verifies the compatiblity mouse events are sent correctly when the node is deleted on pointer event handler.
+Verifies the compatibility mouse events are sent correctly when the node is deleted on pointer event handler.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
diff --git a/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-node-remove.html b/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-node-remove.html
index 80506e09..58f0dc5 100644
--- a/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-node-remove.html
+++ b/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-node-remove.html
@@ -18,7 +18,7 @@
 <div id="console"></div>
 
 <script>
-description("Verifies the compatiblity mouse events are sent correctly when the node is deleted on pointer event handler.");
+description("Verifies the compatibility mouse events are sent correctly when the node is deleted on pointer event handler.");
 
 var eventList = ["mousedown", "mouseup", "mousemove",
                  "pointerdown", "pointerup", "pointermove"];
diff --git a/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-on-object.html b/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-on-object.html
index bfc893a..2a2a7997 100644
--- a/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-on-object.html
+++ b/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-on-object.html
@@ -10,7 +10,7 @@
 }
 </style>
 
-<h1>Verifies that mouse activites on an object fire pointerevents</h1>
+<h1>Verifies that mouse activities on an object fire pointerevents</h1>
 
 <object id="obj"></object>
 
@@ -57,5 +57,5 @@
   }
 
   done();
-}, "Verifies that mouse activites on an object fire pointerevents");
+}, "Verifies that mouse activities on an object fire pointerevents");
 </script>
diff --git a/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-on-scrollbar-expected.txt b/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-on-scrollbar-expected.txt
index 91d11513..b9a7dc8 100644
--- a/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-on-scrollbar-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-on-scrollbar-expected.txt
@@ -1,4 +1,4 @@
-Verifies that pointerup/down are fired correctly for correponding mouse events on the scollbar.
+Verifies that pointerup/down are fired correctly for corresponding mouse events on the scollbar.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
diff --git a/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-on-scrollbar.html b/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-on-scrollbar.html
index 86e12f8..ea9e716 100644
--- a/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-on-scrollbar.html
+++ b/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-on-scrollbar.html
@@ -19,7 +19,7 @@
 <div id="console"></div>
 
 <script>
-description("Verifies that pointerup/down are fired correctly for correponding mouse events on the scollbar.");
+description("Verifies that pointerup/down are fired correctly for corresponding mouse events on the scollbar.");
 var targetDiv = document.getElementById('target');
 
 function init() {
diff --git a/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-transition-events-expected.txt b/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-transition-events-expected.txt
index 6097f4a..a68cd20 100644
--- a/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-transition-events-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-transition-events-expected.txt
@@ -1,4 +1,4 @@
-Verifies that pointerenter/leave/over/out are fired correctly for correponding mouse events.
+Verifies that pointerenter/leave/over/out are fired correctly for corresponding mouse events.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
diff --git a/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-transition-events.html b/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-transition-events.html
index 6320528..e0b92f9 100644
--- a/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-transition-events.html
+++ b/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-transition-events.html
@@ -16,7 +16,7 @@
 <div id="console"></div>
 
 <script>
-description("Verifies that pointerenter/leave/over/out are fired correctly for correponding mouse events.");
+description("Verifies that pointerenter/leave/over/out are fired correctly for corresponding mouse events.");
 
 function phaseString(eventPhase) {
   if (eventPhase == Event.NONE)
diff --git a/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-updown-events-expected.txt b/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-updown-events-expected.txt
index 0e571d6..f7dcd79 100644
--- a/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-updown-events-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-updown-events-expected.txt
@@ -1,4 +1,4 @@
-Verifies that pointerup/down are fired correctly for correponding mouse events.
+Verifies that pointerup/down are fired correctly for corresponding mouse events.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
diff --git a/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-updown-events.html b/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-updown-events.html
index 6789de1..50c70df 100644
--- a/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-updown-events.html
+++ b/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-updown-events.html
@@ -16,7 +16,7 @@
 <div id="console"></div>
 
 <script>
-description("Verifies that pointerup/down are fired correctly for correponding mouse events.");
+description("Verifies that pointerup/down are fired correctly for corresponding mouse events.");
 
 function init() {
   var eventList = ["mousedown", "mouseup", "pointerdown", "pointerup"];
diff --git a/third_party/WebKit/LayoutTests/fast/events/pointerevents/pointer-event-properties-in-iframe-expected.txt b/third_party/WebKit/LayoutTests/fast/events/pointerevents/pointer-event-properties-in-iframe-expected.txt
index 6851555..ab8f772 100644
--- a/third_party/WebKit/LayoutTests/fast/events/pointerevents/pointer-event-properties-in-iframe-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/events/pointerevents/pointer-event-properties-in-iframe-expected.txt
@@ -9,139 +9,139 @@
 TEST COMPLETE
 ===== scrollX=25, scrollY=100, zoomFactor=1
  *** Mouse events inside iframe ***
-pointermove of mouse is recieved:
+pointermove of mouse is received:
 clientX = 150
 clientY = 100
 view.name = innerFrame
-mousemove is recieved:
+mousemove is received:
 clientX = 150
 clientY = 100
-pointerdown of mouse is recieved:
+pointerdown of mouse is received:
 clientX = 150
 clientY = 100
 view.name = innerFrame
-mousedown is recieved:
+mousedown is received:
 clientX = 150
 clientY = 100
-pointerup of mouse is recieved:
+pointerup of mouse is received:
 clientX = 150
 clientY = 100
 view.name = innerFrame
-mouseup is recieved:
+mouseup is received:
 clientX = 150
 clientY = 100
  *** Touch events inside iframe ***
-pointerdown of touch is recieved:
+pointerdown of touch is received:
 clientX = 150
 clientY = 100
 view.name = innerFrame
-touchstart is recieved:
+touchstart is received:
 clientX = 150
 clientY = 100
-pointermove of touch is recieved:
+pointermove of touch is received:
 clientX = 150
 clientY = 100
 view.name = innerFrame
-touchmove is recieved:
+touchmove is received:
 clientX = 150
 clientY = 100
-pointerup of touch is recieved:
+pointerup of touch is received:
 clientX = 150
 clientY = 100
 view.name = innerFrame
-touchend is recieved:
+touchend is received:
 clientX = 150
 clientY = 100
 
 ===== scrollX=40, scrollY=140, zoomFactor=1
  *** Mouse events inside iframe ***
-pointermove of mouse is recieved:
+pointermove of mouse is received:
 clientX = 150
 clientY = 100
 view.name = innerFrame
-mousemove is recieved:
+mousemove is received:
 clientX = 150
 clientY = 100
-pointerdown of mouse is recieved:
+pointerdown of mouse is received:
 clientX = 150
 clientY = 100
 view.name = innerFrame
-mousedown is recieved:
+mousedown is received:
 clientX = 150
 clientY = 100
-pointerup of mouse is recieved:
+pointerup of mouse is received:
 clientX = 150
 clientY = 100
 view.name = innerFrame
-mouseup is recieved:
+mouseup is received:
 clientX = 150
 clientY = 100
  *** Touch events inside iframe ***
-pointerdown of touch is recieved:
+pointerdown of touch is received:
 clientX = 150
 clientY = 100
 view.name = innerFrame
-touchstart is recieved:
+touchstart is received:
 clientX = 150
 clientY = 100
-pointermove of touch is recieved:
+pointermove of touch is received:
 clientX = 150
 clientY = 100
 view.name = innerFrame
-touchmove is recieved:
+touchmove is received:
 clientX = 150
 clientY = 100
-pointerup of touch is recieved:
+pointerup of touch is received:
 clientX = 150
 clientY = 100
 view.name = innerFrame
-touchend is recieved:
+touchend is received:
 clientX = 150
 clientY = 100
 
 ===== scrollX=40, scrollY=140, zoomFactor=2
  *** Mouse events inside iframe ***
-pointermove of mouse is recieved:
+pointermove of mouse is received:
 clientX = 50
 clientY = 0
 view.name = innerFrame
-mousemove is recieved:
+mousemove is received:
 clientX = 50
 clientY = 0
-pointerdown of mouse is recieved:
+pointerdown of mouse is received:
 clientX = 50
 clientY = 0
 view.name = innerFrame
-mousedown is recieved:
+mousedown is received:
 clientX = 50
 clientY = 0
-pointerup of mouse is recieved:
+pointerup of mouse is received:
 clientX = 50
 clientY = 0
 view.name = innerFrame
-mouseup is recieved:
+mouseup is received:
 clientX = 50
 clientY = 0
  *** Touch events inside iframe ***
-pointerdown of touch is recieved:
+pointerdown of touch is received:
 clientX = 50
 clientY = 0
 view.name = innerFrame
-touchstart is recieved:
+touchstart is received:
 clientX = 50
 clientY = 0
-pointermove of touch is recieved:
+pointermove of touch is received:
 clientX = 50
 clientY = 0
 view.name = innerFrame
-touchmove is recieved:
+touchmove is received:
 clientX = 50
 clientY = 0
-pointerup of touch is recieved:
+pointerup of touch is received:
 clientX = 50
 clientY = 0
 view.name = innerFrame
-touchend is recieved:
+touchend is received:
 clientX = 50
 clientY = 0
 
diff --git a/third_party/WebKit/LayoutTests/fast/events/pointerevents/pointer-event-properties-in-iframe.html b/third_party/WebKit/LayoutTests/fast/events/pointerevents/pointer-event-properties-in-iframe.html
index 01b6631..222b194 100644
--- a/third_party/WebKit/LayoutTests/fast/events/pointerevents/pointer-event-properties-in-iframe.html
+++ b/third_party/WebKit/LayoutTests/fast/events/pointerevents/pointer-event-properties-in-iframe.html
@@ -77,18 +77,18 @@
 {
   document.events.forEach(function(event) {
     if (event.type.startsWith('pointer')) {
-      debug(event.type + " of " + event.pointerType + " is recieved:");
+      debug(event.type + " of " + event.pointerType + " is received:");
       attributes.forEach(function(att) {
         debug(att + " = " + event[att]);
       });
       debug("view.name = " + event.view.name);
     } else if (event.type.startsWith('touch')) {
-      debug(event.type + " is recieved:");
+      debug(event.type + " is received:");
       attributes.forEach(function(att) {
         debug(att + " = " + event.changedTouches[0][att]);
       });
     } else {
-      debug(event.type + " is recieved:");
+      debug(event.type + " is received:");
       attributes.forEach(function(att) {
         debug(att + " = " + event[att]);
       });
diff --git a/third_party/WebKit/LayoutTests/fast/events/pointerevents/touch-capture-in-iframe-expected.txt b/third_party/WebKit/LayoutTests/fast/events/pointerevents/touch-capture-in-iframe-expected.txt
index 4ca7b7c5..95a0363 100644
--- a/third_party/WebKit/LayoutTests/fast/events/pointerevents/touch-capture-in-iframe-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/events/pointerevents/touch-capture-in-iframe-expected.txt
@@ -9,289 +9,289 @@
 TEST COMPLETE
 ==== Finger1 in innerFrame and Finger2 in outerFrame ====
 *** Put first finger down in innerFrame and move ***
-innerFrame recieved pointerdown with id=2
-touchstart is recieved with changedTouches.length=1:
+innerFrame received pointerdown with id=2
+touchstart is received with changedTouches.length=1:
   Touch with id=0 with target = innerFrame
-innerFrame recieved gotpointercapture with id=2
-innerFrame recieved pointermove with id=2
-touchmove is recieved with changedTouches.length=1:
+innerFrame received gotpointercapture with id=2
+innerFrame received pointermove with id=2
+touchmove is received with changedTouches.length=1:
   Touch with id=0 with target = innerFrame
 
 *** Put second finger in outerFrame and move ***
-outerFrame recieved pointerdown with id=3
-outerFrame recieved gotpointercapture with id=3
-outerFrame recieved pointermove with id=3
+outerFrame received pointerdown with id=3
+outerFrame received gotpointercapture with id=3
+outerFrame received pointermove with id=3
 
 *** Move first finger to outerFrame ***
-innerFrame recieved pointermove with id=2
-touchmove is recieved with changedTouches.length=1:
+innerFrame received pointermove with id=2
+touchmove is received with changedTouches.length=1:
   Touch with id=0 with target = innerFrame
 
 *** Move second finger to innerFrame ***
-outerFrame recieved pointermove with id=3
+outerFrame received pointermove with id=3
 
 *** Releasing fingers ***
-innerFrame recieved pointerup with id=2
-innerFrame recieved lostpointercapture with id=2
-outerFrame recieved pointerup with id=3
-outerFrame recieved lostpointercapture with id=3
-touchend is recieved with changedTouches.length=1:
+innerFrame received pointerup with id=2
+innerFrame received lostpointercapture with id=2
+outerFrame received pointerup with id=3
+outerFrame received lostpointercapture with id=3
+touchend is received with changedTouches.length=1:
   Touch with id=0 with target = innerFrame
 
 ==== Finger1 in outerFrame and Finger2 in innerFrame ====
 *** Put first finger down in outerFrame and move ***
-outerFrame recieved pointerdown with id=4
-touchstart is recieved with changedTouches.length=1:
+outerFrame received pointerdown with id=4
+touchstart is received with changedTouches.length=1:
   Touch with id=0 with target = outerFrame
-outerFrame recieved gotpointercapture with id=4
-outerFrame recieved pointermove with id=4
-touchmove is recieved with changedTouches.length=1:
+outerFrame received gotpointercapture with id=4
+outerFrame received pointermove with id=4
+touchmove is received with changedTouches.length=1:
   Touch with id=0 with target = outerFrame
 
 *** Put second finger in innerFrame and move ***
-innerFrame recieved pointerdown with id=5
-touchstart is recieved with changedTouches.length=1:
+innerFrame received pointerdown with id=5
+touchstart is received with changedTouches.length=1:
   Touch with id=1 with target = innerFrameElement
-innerFrame recieved gotpointercapture with id=5
-innerFrame recieved pointermove with id=5
-touchmove is recieved with changedTouches.length=1:
+innerFrame received gotpointercapture with id=5
+innerFrame received pointermove with id=5
+touchmove is received with changedTouches.length=1:
   Touch with id=1 with target = innerFrameElement
 
 *** Move first finger to innerFrame ***
-outerFrame recieved pointermove with id=4
-touchmove is recieved with changedTouches.length=1:
+outerFrame received pointermove with id=4
+touchmove is received with changedTouches.length=1:
   Touch with id=0 with target = outerFrame
 
 *** Move second finger to outerFrame ***
-innerFrame recieved pointermove with id=5
-touchmove is recieved with changedTouches.length=1:
+innerFrame received pointermove with id=5
+touchmove is received with changedTouches.length=1:
   Touch with id=1 with target = innerFrameElement
 
 *** Releasing fingers ***
-outerFrame recieved pointerup with id=4
-outerFrame recieved lostpointercapture with id=4
-innerFrame recieved pointerup with id=5
-innerFrame recieved lostpointercapture with id=5
-touchend is recieved with changedTouches.length=2:
+outerFrame received pointerup with id=4
+outerFrame received lostpointercapture with id=4
+innerFrame received pointerup with id=5
+innerFrame received lostpointercapture with id=5
+touchend is received with changedTouches.length=2:
   Touch with id=0 with target = outerFrame
   Touch with id=1 with target = innerFrameElement
-touchend is recieved with changedTouches.length=2:
+touchend is received with changedTouches.length=2:
   Touch with id=0 with target = outerFrame
   Touch with id=1 with target = innerFrameElement
 
 ==== Finger1 in innerFrame and Finger2 in innerFrame ====
 *** Put first finger down in innerFrame and move ***
-innerFrame recieved pointerdown with id=6
-touchstart is recieved with changedTouches.length=1:
+innerFrame received pointerdown with id=6
+touchstart is received with changedTouches.length=1:
   Touch with id=0 with target = innerFrame
-innerFrame recieved gotpointercapture with id=6
-innerFrame recieved pointermove with id=6
-touchmove is recieved with changedTouches.length=1:
+innerFrame received gotpointercapture with id=6
+innerFrame received pointermove with id=6
+touchmove is received with changedTouches.length=1:
   Touch with id=0 with target = innerFrame
 
 *** Put second finger in innerFrame and move ***
-innerFrame recieved pointerdown with id=7
-touchstart is recieved with changedTouches.length=1:
+innerFrame received pointerdown with id=7
+touchstart is received with changedTouches.length=1:
   Touch with id=1 with target = innerFrame
-innerFrame recieved gotpointercapture with id=7
-innerFrame recieved pointermove with id=7
-touchmove is recieved with changedTouches.length=1:
+innerFrame received gotpointercapture with id=7
+innerFrame received pointermove with id=7
+touchmove is received with changedTouches.length=1:
   Touch with id=1 with target = innerFrame
 
 *** Move first finger to outerFrame ***
-innerFrame recieved pointermove with id=6
-touchmove is recieved with changedTouches.length=1:
+innerFrame received pointermove with id=6
+touchmove is received with changedTouches.length=1:
   Touch with id=0 with target = innerFrame
 
 *** Move second finger to outerFrame ***
-innerFrame recieved pointermove with id=7
-touchmove is recieved with changedTouches.length=1:
+innerFrame received pointermove with id=7
+touchmove is received with changedTouches.length=1:
   Touch with id=1 with target = innerFrame
 
 *** Releasing fingers ***
-innerFrame recieved pointerup with id=6
-innerFrame recieved lostpointercapture with id=6
-innerFrame recieved pointerup with id=7
-innerFrame recieved lostpointercapture with id=7
-touchend is recieved with changedTouches.length=2:
+innerFrame received pointerup with id=6
+innerFrame received lostpointercapture with id=6
+innerFrame received pointerup with id=7
+innerFrame received lostpointercapture with id=7
+touchend is received with changedTouches.length=2:
   Touch with id=0 with target = innerFrame
   Touch with id=1 with target = innerFrame
 
 ==== Finger1 in outerFrame and Finger2 in outerFrame ====
 *** Put first finger down in outerFrame and move ***
-outerFrame recieved pointerdown with id=8
-touchstart is recieved with changedTouches.length=1:
+outerFrame received pointerdown with id=8
+touchstart is received with changedTouches.length=1:
   Touch with id=0 with target = outerFrame
-outerFrame recieved gotpointercapture with id=8
-outerFrame recieved pointermove with id=8
-touchmove is recieved with changedTouches.length=1:
+outerFrame received gotpointercapture with id=8
+outerFrame received pointermove with id=8
+touchmove is received with changedTouches.length=1:
   Touch with id=0 with target = outerFrame
 
 *** Put second finger in outerFrame and move ***
-outerFrame recieved pointerdown with id=9
-touchstart is recieved with changedTouches.length=1:
+outerFrame received pointerdown with id=9
+touchstart is received with changedTouches.length=1:
   Touch with id=1 with target = outerFrame
-outerFrame recieved gotpointercapture with id=9
-outerFrame recieved pointermove with id=9
-touchmove is recieved with changedTouches.length=1:
+outerFrame received gotpointercapture with id=9
+outerFrame received pointermove with id=9
+touchmove is received with changedTouches.length=1:
   Touch with id=1 with target = outerFrame
 
 *** Move first finger to innerFrame ***
-outerFrame recieved pointermove with id=8
-touchmove is recieved with changedTouches.length=1:
+outerFrame received pointermove with id=8
+touchmove is received with changedTouches.length=1:
   Touch with id=0 with target = outerFrame
 
 *** Move second finger to innerFrame ***
-outerFrame recieved pointermove with id=9
-touchmove is recieved with changedTouches.length=1:
+outerFrame received pointermove with id=9
+touchmove is received with changedTouches.length=1:
   Touch with id=1 with target = outerFrame
 
 *** Releasing fingers ***
-outerFrame recieved pointerup with id=8
-outerFrame recieved lostpointercapture with id=8
-outerFrame recieved pointerup with id=9
-outerFrame recieved lostpointercapture with id=9
-touchend is recieved with changedTouches.length=2:
+outerFrame received pointerup with id=8
+outerFrame received lostpointercapture with id=8
+outerFrame received pointerup with id=9
+outerFrame received lostpointercapture with id=9
+touchend is received with changedTouches.length=2:
   Touch with id=0 with target = outerFrame
   Touch with id=1 with target = outerFrame
 
 ==== Finger1 in innerFrame and Finger2 in outerFrame with releaseTouchCapture ====
 *** Put first finger down in innerFrame and move ***
 --- Release pointer capture for 10 ---
-innerFrame recieved pointerdown with id=10
-touchstart is recieved with changedTouches.length=1:
+innerFrame received pointerdown with id=10
+touchstart is received with changedTouches.length=1:
   Touch with id=0 with target = innerFrame
-innerFrame recieved pointermove with id=10
-touchmove is recieved with changedTouches.length=1:
+innerFrame received pointermove with id=10
+touchmove is received with changedTouches.length=1:
   Touch with id=0 with target = innerFrame
 
 *** Put second finger in outerFrame and move ***
 --- Release pointer capture for 11 ---
-outerFrame recieved pointerdown with id=11
-outerFrame recieved pointermove with id=11
+outerFrame received pointerdown with id=11
+outerFrame received pointermove with id=11
 
 *** Move first finger to outerFrame ***
-outerFrame recieved pointermove with id=10
-touchmove is recieved with changedTouches.length=1:
+outerFrame received pointermove with id=10
+touchmove is received with changedTouches.length=1:
   Touch with id=0 with target = innerFrame
 
 *** Move second finger to innerFrame ***
-innerFrame recieved pointermove with id=11
+innerFrame received pointermove with id=11
 
 *** Releasing fingers ***
-outerFrame recieved pointerup with id=10
-innerFrame recieved pointerup with id=11
-touchend is recieved with changedTouches.length=1:
+outerFrame received pointerup with id=10
+innerFrame received pointerup with id=11
+touchend is received with changedTouches.length=1:
   Touch with id=0 with target = innerFrame
 
 ==== Finger1 in outerFrame and Finger2 in innerFrame with releaseTouchCapture ====
 *** Put first finger down in outerFrame and move ***
 --- Release pointer capture for 12 ---
-outerFrame recieved pointerdown with id=12
-touchstart is recieved with changedTouches.length=1:
+outerFrame received pointerdown with id=12
+touchstart is received with changedTouches.length=1:
   Touch with id=0 with target = outerFrame
-outerFrame recieved pointermove with id=12
-touchmove is recieved with changedTouches.length=1:
+outerFrame received pointermove with id=12
+touchmove is received with changedTouches.length=1:
   Touch with id=0 with target = outerFrame
 
 *** Put second finger in innerFrame and move ***
 --- Release pointer capture for 13 ---
-innerFrame recieved pointerdown with id=13
-touchstart is recieved with changedTouches.length=1:
+innerFrame received pointerdown with id=13
+touchstart is received with changedTouches.length=1:
   Touch with id=1 with target = innerFrameElement
-innerFrame recieved pointermove with id=13
-touchmove is recieved with changedTouches.length=1:
+innerFrame received pointermove with id=13
+touchmove is received with changedTouches.length=1:
   Touch with id=1 with target = innerFrameElement
 
 *** Move first finger to innerFrame ***
-innerFrame recieved pointermove with id=12
-touchmove is recieved with changedTouches.length=1:
+innerFrame received pointermove with id=12
+touchmove is received with changedTouches.length=1:
   Touch with id=0 with target = outerFrame
 
 *** Move second finger to outerFrame ***
-outerFrame recieved pointermove with id=13
-touchmove is recieved with changedTouches.length=1:
+outerFrame received pointermove with id=13
+touchmove is received with changedTouches.length=1:
   Touch with id=1 with target = innerFrameElement
 
 *** Releasing fingers ***
-innerFrame recieved pointerup with id=12
-outerFrame recieved pointerup with id=13
-touchend is recieved with changedTouches.length=2:
+innerFrame received pointerup with id=12
+outerFrame received pointerup with id=13
+touchend is received with changedTouches.length=2:
   Touch with id=0 with target = outerFrame
   Touch with id=1 with target = innerFrameElement
-touchend is recieved with changedTouches.length=2:
+touchend is received with changedTouches.length=2:
   Touch with id=0 with target = outerFrame
   Touch with id=1 with target = innerFrameElement
 
 ==== Finger1 in innerFrame and Finger2 in innerFrame with releaseTouchCapture ====
 *** Put first finger down in innerFrame and move ***
 --- Release pointer capture for 14 ---
-innerFrame recieved pointerdown with id=14
-touchstart is recieved with changedTouches.length=1:
+innerFrame received pointerdown with id=14
+touchstart is received with changedTouches.length=1:
   Touch with id=0 with target = innerFrame
-innerFrame recieved pointermove with id=14
-touchmove is recieved with changedTouches.length=1:
+innerFrame received pointermove with id=14
+touchmove is received with changedTouches.length=1:
   Touch with id=0 with target = innerFrame
 
 *** Put second finger in innerFrame and move ***
 --- Release pointer capture for 15 ---
-innerFrame recieved pointerdown with id=15
-touchstart is recieved with changedTouches.length=1:
+innerFrame received pointerdown with id=15
+touchstart is received with changedTouches.length=1:
   Touch with id=1 with target = innerFrame
-innerFrame recieved pointermove with id=15
-touchmove is recieved with changedTouches.length=1:
+innerFrame received pointermove with id=15
+touchmove is received with changedTouches.length=1:
   Touch with id=1 with target = innerFrame
 
 *** Move first finger to outerFrame ***
-outerFrame recieved pointermove with id=14
-touchmove is recieved with changedTouches.length=1:
+outerFrame received pointermove with id=14
+touchmove is received with changedTouches.length=1:
   Touch with id=0 with target = innerFrame
 
 *** Move second finger to outerFrame ***
-outerFrame recieved pointermove with id=15
-touchmove is recieved with changedTouches.length=1:
+outerFrame received pointermove with id=15
+touchmove is received with changedTouches.length=1:
   Touch with id=1 with target = innerFrame
 
 *** Releasing fingers ***
-outerFrame recieved pointerup with id=14
-outerFrame recieved pointerup with id=15
-touchend is recieved with changedTouches.length=2:
+outerFrame received pointerup with id=14
+outerFrame received pointerup with id=15
+touchend is received with changedTouches.length=2:
   Touch with id=0 with target = innerFrame
   Touch with id=1 with target = innerFrame
 
 ==== Finger1 in outerFrame and Finger2 in outerFrame with releaseTouchCapture ====
 *** Put first finger down in outerFrame and move ***
 --- Release pointer capture for 16 ---
-outerFrame recieved pointerdown with id=16
-touchstart is recieved with changedTouches.length=1:
+outerFrame received pointerdown with id=16
+touchstart is received with changedTouches.length=1:
   Touch with id=0 with target = outerFrame
-outerFrame recieved pointermove with id=16
-touchmove is recieved with changedTouches.length=1:
+outerFrame received pointermove with id=16
+touchmove is received with changedTouches.length=1:
   Touch with id=0 with target = outerFrame
 
 *** Put second finger in outerFrame and move ***
 --- Release pointer capture for 17 ---
-outerFrame recieved pointerdown with id=17
-touchstart is recieved with changedTouches.length=1:
+outerFrame received pointerdown with id=17
+touchstart is received with changedTouches.length=1:
   Touch with id=1 with target = outerFrame
-outerFrame recieved pointermove with id=17
-touchmove is recieved with changedTouches.length=1:
+outerFrame received pointermove with id=17
+touchmove is received with changedTouches.length=1:
   Touch with id=1 with target = outerFrame
 
 *** Move first finger to innerFrame ***
-innerFrame recieved pointermove with id=16
-touchmove is recieved with changedTouches.length=1:
+innerFrame received pointermove with id=16
+touchmove is received with changedTouches.length=1:
   Touch with id=0 with target = outerFrame
 
 *** Move second finger to innerFrame ***
-innerFrame recieved pointermove with id=17
-touchmove is recieved with changedTouches.length=1:
+innerFrame received pointermove with id=17
+touchmove is received with changedTouches.length=1:
   Touch with id=1 with target = outerFrame
 
 *** Releasing fingers ***
-innerFrame recieved pointerup with id=16
-innerFrame recieved pointerup with id=17
-touchend is recieved with changedTouches.length=2:
+innerFrame received pointerup with id=16
+innerFrame received pointerup with id=17
+touchend is received with changedTouches.length=2:
   Touch with id=0 with target = outerFrame
   Touch with id=1 with target = outerFrame
 
diff --git a/third_party/WebKit/LayoutTests/fast/events/pointerevents/touch-capture-in-iframe.html b/third_party/WebKit/LayoutTests/fast/events/pointerevents/touch-capture-in-iframe.html
index b9aa1ca..8f72ba1 100644
--- a/third_party/WebKit/LayoutTests/fast/events/pointerevents/touch-capture-in-iframe.html
+++ b/third_party/WebKit/LayoutTests/fast/events/pointerevents/touch-capture-in-iframe.html
@@ -44,9 +44,9 @@
 
 function logEvent(event) {
   if (event.type.includes('pointer')) {
-    debug(event.target.id + ' recieved ' + event.type + ' with id=' + event.pointerId);
+    debug(event.target.id + ' received ' + event.type + ' with id=' + event.pointerId);
   } else if (event.type.startsWith('touch')) {
-    debug(event.type + ' is recieved with changedTouches.length=' + event.changedTouches.length + ':');
+    debug(event.type + ' is received with changedTouches.length=' + event.changedTouches.length + ':');
     for(var i=0; i<event.changedTouches.length; i++) {
       debug('  Touch with id=' + event.changedTouches[i].identifier + ' with target = ' + event.changedTouches[i].target.id);
     }
diff --git a/third_party/WebKit/LayoutTests/fast/events/popup-blocking-click-in-iframe-expected.txt b/third_party/WebKit/LayoutTests/fast/events/popup-blocking-click-in-iframe-expected.txt
index fe229cd1..c1a0c816 100644
--- a/third_party/WebKit/LayoutTests/fast/events/popup-blocking-click-in-iframe-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/events/popup-blocking-click-in-iframe-expected.txt
@@ -1,5 +1,5 @@
 
-This tests that popup blocking does not supress windows opened in an iframe if the event handler is a function from an enclosing frame.
+This tests that popup blocking does not suppress windows opened in an iframe if the event handler is a function from an enclosing frame.
 
 To run manually click the link in the iframe above with popup blocking enabled.
 
diff --git a/third_party/WebKit/LayoutTests/fast/events/popup-blocking-click-in-iframe.html b/third_party/WebKit/LayoutTests/fast/events/popup-blocking-click-in-iframe.html
index 3d85fb3..fed70e3 100644
--- a/third_party/WebKit/LayoutTests/fast/events/popup-blocking-click-in-iframe.html
+++ b/third_party/WebKit/LayoutTests/fast/events/popup-blocking-click-in-iframe.html
@@ -53,7 +53,7 @@
     <body style="border: 0; margin: 0" onload="test()">
         <iframe style="border: 0; margin: 0" src="resources/popup-blocking-click-in-iframe-otherFrame.html" name="otherFrame"></iframe>
 
-        <p>This tests that popup blocking does not supress windows opened in an iframe if the event handler is a function from an enclosing frame.</p>
+        <p>This tests that popup blocking does not suppress windows opened in an iframe if the event handler is a function from an enclosing frame.</p>
         <p>To run manually click the link in the iframe above with popup blocking enabled.</p>
         <div id="res"></div>
     </body>
diff --git a/third_party/WebKit/LayoutTests/fast/events/scroll-to-anchor-in-overflow-hidden.html b/third_party/WebKit/LayoutTests/fast/events/scroll-to-anchor-in-overflow-hidden.html
index d9ad7d9..e5b2a9d 100644
--- a/third_party/WebKit/LayoutTests/fast/events/scroll-to-anchor-in-overflow-hidden.html
+++ b/third_party/WebKit/LayoutTests/fast/events/scroll-to-anchor-in-overflow-hidden.html
@@ -36,7 +36,7 @@
            }
 
            if (document.scrollingElement.scrollTop == 0)
-               log("Automated test : FAILED  : no scroll has occured ");
+               log("Automated test : FAILED  : no scroll has occurred ");
            else
                log("Automated test : PASSED");
 
diff --git a/third_party/WebKit/LayoutTests/fast/events/touch/compositor-touch-hit-rects-scroll.html b/third_party/WebKit/LayoutTests/fast/events/touch/compositor-touch-hit-rects-scroll.html
index 6ad5898a..3042c24 100644
--- a/third_party/WebKit/LayoutTests/fast/events/touch/compositor-touch-hit-rects-scroll.html
+++ b/third_party/WebKit/LayoutTests/fast/events/touch/compositor-touch-hit-rects-scroll.html
@@ -90,7 +90,7 @@
 
 // Scroll after layout has finished.
 preRunHandlerForTest['scrollContent'] = function(e) {
-    // Scroll so the rect is visible but slighly clipped.
+    // Scroll so the rect is visible but slightly clipped.
     document.getElementById('scroll1').scrollTop = 15;
 };
 
diff --git a/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-tap-frame-removed-expected.txt b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-tap-frame-removed-expected.txt
index 8fc0538..aa4c6432 100644
--- a/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-tap-frame-removed-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-tap-frame-removed-expected.txt
@@ -1,5 +1,5 @@
 
-Verifies that a tap occuring on an iframe that gets removed during tap handling doesn't cause a crash.
+Verifies that a tap occurring on an iframe that gets removed during tap handling doesn't cause a crash.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
diff --git a/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-tap-frame-removed.html b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-tap-frame-removed.html
index ea456748..80d0e394 100644
--- a/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-tap-frame-removed.html
+++ b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-tap-frame-removed.html
@@ -29,7 +29,7 @@
 document.addEventListener('mouseup', eventLogger);
 document.addEventListener('click', eventLogger);
 
-description("Verifies that a tap occuring on an iframe that gets removed during tap handling doesn't cause a crash.");
+description("Verifies that a tap occurring on an iframe that gets removed during tap handling doesn't cause a crash.");
 
 var rect = target.getBoundingClientRect();
 var point = {
diff --git a/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-tap-frame-scrolled-expected.txt b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-tap-frame-scrolled-expected.txt
index f00b8c3..9f4a556 100644
--- a/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-tap-frame-scrolled-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-tap-frame-scrolled-expected.txt
@@ -1,5 +1,5 @@
 
-Verifies that a tap occuring in a scrolled iframe has the correct co-ordinates
+Verifies that a tap occurring in a scrolled iframe has the correct co-ordinates
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
diff --git a/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-tap-frame-scrolled.html b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-tap-frame-scrolled.html
index 126b370a..ef5e461 100644
--- a/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-tap-frame-scrolled.html
+++ b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-tap-frame-scrolled.html
@@ -50,7 +50,7 @@
     shouldBe("event.pageY", "pointInFrame.y + frameScrollOffset.y");
 }
 
-description("Verifies that a tap occuring in a scrolled iframe has the correct co-ordinates");
+description("Verifies that a tap occurring in a scrolled iframe has the correct co-ordinates");
 
 if (window.eventSender) {
     jsTestIsAsync = true;
diff --git a/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-tap-scrolled-expected.txt b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-tap-scrolled-expected.txt
index cba4df2..ff0529f8 100644
--- a/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-tap-scrolled-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-tap-scrolled-expected.txt
@@ -1,4 +1,4 @@
-Verifies that a tap occuring in a scrolled page has the correct co-ordinates
+Verifies that a tap occurring in a scrolled page has the correct co-ordinates
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
diff --git a/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-tap-scrolled.html b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-tap-scrolled.html
index f997c172..1f1ec1c 100644
--- a/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-tap-scrolled.html
+++ b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-tap-scrolled.html
@@ -37,7 +37,7 @@
 for (var i = 0; i < eventTypes.length; i++)
     document.addEventListener(eventTypes[i],onEvent);
 
-description("Verifies that a tap occuring in a scrolled page has the correct co-ordinates");
+description("Verifies that a tap occurring in a scrolled page has the correct co-ordinates");
 
 if (window.eventSender) {
     jsTestIsAsync = true;
diff --git a/third_party/WebKit/LayoutTests/fast/events/touch/multi-touch-partial-sequence.html b/third_party/WebKit/LayoutTests/fast/events/touch/multi-touch-partial-sequence.html
index b3e2f66..c63e68b 100644
--- a/third_party/WebKit/LayoutTests/fast/events/touch/multi-touch-partial-sequence.html
+++ b/third_party/WebKit/LayoutTests/fast/events/touch/multi-touch-partial-sequence.html
@@ -30,7 +30,7 @@
     shouldBe('event.target', 'target');
 
     // Touch ID 0 is the one we never got a touchstart for, so it should
-    // be targetted at the document.
+    // be targeted at the document.
     shouldBe('event.touches.length', '2');
     shouldBe('event.touches[0].identifier', '0');
     shouldBe('event.touches[0].pageX', '12');
diff --git a/third_party/WebKit/LayoutTests/fast/events/touch/resources/compositor-touch-hit-rects-iframe.html b/third_party/WebKit/LayoutTests/fast/events/touch/resources/compositor-touch-hit-rects-iframe.html
index 73c20f1a..3ac924f 100644
--- a/third_party/WebKit/LayoutTests/fast/events/touch/resources/compositor-touch-hit-rects-iframe.html
+++ b/third_party/WebKit/LayoutTests/fast/events/touch/resources/compositor-touch-hit-rects-iframe.html
@@ -30,7 +30,7 @@
   frameElement.removeHandlers = function() {
     document.getElementById('child').removeEventListener('touchstart', handler, false);
   }
-  // Scroll so the div is just slighly clipped.
+  // Scroll so the div is just slightly clipped.
   document.scrollingElement.scrollTop = 40;
   </script>
 </body>
diff --git a/third_party/WebKit/LayoutTests/fast/files/workers/worker-read-blob-async-crash-expected.txt b/third_party/WebKit/LayoutTests/fast/files/workers/worker-read-blob-async-crash-expected.txt
index 8897afc..bf9797e 100644
--- a/third_party/WebKit/LayoutTests/fast/files/workers/worker-read-blob-async-crash-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/files/workers/worker-read-blob-async-crash-expected.txt
@@ -1,7 +1,7 @@
 PASS successfullyParsed is true
 
 TEST COMPLETE
-Test for crash bug in WorkerThreadableLoader::MainThreadBridge::mainThreadCreateLoader when FileReader is runing in the worker thread and the page location is changed.
+Test for crash bug in WorkerThreadableLoader::MainThreadBridge::mainThreadCreateLoader when FileReader is running in the worker thread and the page location is changed.
 
 This test PASSED if it did not crash.
 
diff --git a/third_party/WebKit/LayoutTests/fast/files/workers/worker-read-blob-async-crash.html b/third_party/WebKit/LayoutTests/fast/files/workers/worker-read-blob-async-crash.html
index fef912a..b36a0278 100644
--- a/third_party/WebKit/LayoutTests/fast/files/workers/worker-read-blob-async-crash.html
+++ b/third_party/WebKit/LayoutTests/fast/files/workers/worker-read-blob-async-crash.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html>
 <body>
-    <p>Test for crash bug in WorkerThreadableLoader::MainThreadBridge::mainThreadCreateLoader when FileReader is runing in the worker thread and the page location is changed.</p>
+    <p>Test for crash bug in WorkerThreadableLoader::MainThreadBridge::mainThreadCreateLoader when FileReader is running in the worker thread and the page location is changed.</p>
     <p>This test PASSED if it did not crash.</p>
     <script src="../../../resources/js-test.js"></script>
     <script>
diff --git a/third_party/WebKit/LayoutTests/fast/filesystem/not-enough-arguments.html b/third_party/WebKit/LayoutTests/fast/filesystem/not-enough-arguments.html
index 3ef2b31..81a5b806 100644
--- a/third_party/WebKit/LayoutTests/fast/filesystem/not-enough-arguments.html
+++ b/third_party/WebKit/LayoutTests/fast/filesystem/not-enough-arguments.html
@@ -9,7 +9,7 @@
 
 function errorCallback(error)
 {
-    debug("Error occured:" + error.name);
+    debug("Error occurred:" + error.name);
     finishJSTest();
 }
 
diff --git a/third_party/WebKit/LayoutTests/fast/filesystem/null-arguments.html b/third_party/WebKit/LayoutTests/fast/filesystem/null-arguments.html
index 2528801..ea93ef53 100644
--- a/third_party/WebKit/LayoutTests/fast/filesystem/null-arguments.html
+++ b/third_party/WebKit/LayoutTests/fast/filesystem/null-arguments.html
@@ -9,7 +9,7 @@
 
 function errorCallback(error)
 {
-    debug("Error occured: " + error.name);
+    debug("Error occurred: " + error.name);
     finishJSTest();
 }
 
diff --git a/third_party/WebKit/LayoutTests/fast/filesystem/resources/directory-entry-to-uri.js b/third_party/WebKit/LayoutTests/fast/filesystem/resources/directory-entry-to-uri.js
index b30e4023..f0016774 100644
--- a/third_party/WebKit/LayoutTests/fast/filesystem/resources/directory-entry-to-uri.js
+++ b/third_party/WebKit/LayoutTests/fast/filesystem/resources/directory-entry-to-uri.js
@@ -11,7 +11,7 @@
 var testDirectoryURI = null;
 
 function errorCallback(error) {
-    testFailed("Error occured:" + error.name);
+    testFailed("Error occurred:" + error.name);
     finishJSTest();
 }
 
diff --git a/third_party/WebKit/LayoutTests/fast/filesystem/resources/file-entry-to-uri.js b/third_party/WebKit/LayoutTests/fast/filesystem/resources/file-entry-to-uri.js
index de9cfb8..f8d7fb6 100644
--- a/third_party/WebKit/LayoutTests/fast/filesystem/resources/file-entry-to-uri.js
+++ b/third_party/WebKit/LayoutTests/fast/filesystem/resources/file-entry-to-uri.js
@@ -11,7 +11,7 @@
 var testFileURI = null;
 
 function errorCallback(error) {
-    testFailed("Error occured:" + error.name);
+    testFailed("Error occurred:" + error.name);
     finishJSTest();
 }
 
diff --git a/third_party/WebKit/LayoutTests/fast/filesystem/resources/file-from-file-entry.js b/third_party/WebKit/LayoutTests/fast/filesystem/resources/file-from-file-entry.js
index 09cd5f79..ca501fff 100644
--- a/third_party/WebKit/LayoutTests/fast/filesystem/resources/file-from-file-entry.js
+++ b/third_party/WebKit/LayoutTests/fast/filesystem/resources/file-from-file-entry.js
@@ -12,7 +12,7 @@
 var testFile = null;
 
 function errorCallback(error) {
-    testFailed("Error occured:" + error.name);
+    testFailed("Error occurred:" + error.name);
     finishJSTest();
 }
 
diff --git a/third_party/WebKit/LayoutTests/fast/filesystem/resources/read-directory-many.js b/third_party/WebKit/LayoutTests/fast/filesystem/resources/read-directory-many.js
index 4d735e7d..744b3f4 100644
--- a/third_party/WebKit/LayoutTests/fast/filesystem/resources/read-directory-many.js
+++ b/third_party/WebKit/LayoutTests/fast/filesystem/resources/read-directory-many.js
@@ -12,7 +12,7 @@
 
 function errorCallback(error)
 {
-    debug("Error occured:" + error.name);
+    debug("Error occurred:" + error.name);
     endTest();
 }
 
diff --git a/third_party/WebKit/LayoutTests/fast/filesystem/resources/simple-persistent.js b/third_party/WebKit/LayoutTests/fast/filesystem/resources/simple-persistent.js
index 3a839352..f551f13 100644
--- a/third_party/WebKit/LayoutTests/fast/filesystem/resources/simple-persistent.js
+++ b/third_party/WebKit/LayoutTests/fast/filesystem/resources/simple-persistent.js
@@ -9,7 +9,7 @@
 var fileSystem = null;
 
 function errorCallback(error) {
-    debug("Error occured while requesting a PERSISTENT file system:" + error.name);
+    debug("Error occurred while requesting a PERSISTENT file system:" + error.name);
     finishJSTest();
 }
 
diff --git a/third_party/WebKit/LayoutTests/fast/filesystem/resources/simple-required-arguments-getdirectory.js b/third_party/WebKit/LayoutTests/fast/filesystem/resources/simple-required-arguments-getdirectory.js
index 979afb2..41585e99 100644
--- a/third_party/WebKit/LayoutTests/fast/filesystem/resources/simple-required-arguments-getdirectory.js
+++ b/third_party/WebKit/LayoutTests/fast/filesystem/resources/simple-required-arguments-getdirectory.js
@@ -9,7 +9,7 @@
 var fileSystem = null;
 
 function errorCallback(error) {
-    debug("Error occured while requesting a TEMPORARY file system:" + error.name);
+    debug("Error occurred while requesting a TEMPORARY file system:" + error.name);
     finishJSTest();
 }
 
diff --git a/third_party/WebKit/LayoutTests/fast/filesystem/resources/simple-required-arguments-getfile.js b/third_party/WebKit/LayoutTests/fast/filesystem/resources/simple-required-arguments-getfile.js
index 5caf288a..02176a1 100644
--- a/third_party/WebKit/LayoutTests/fast/filesystem/resources/simple-required-arguments-getfile.js
+++ b/third_party/WebKit/LayoutTests/fast/filesystem/resources/simple-required-arguments-getfile.js
@@ -9,7 +9,7 @@
 var fileSystem = null;
 
 function errorCallback(error) {
-    debug("Error occured while requesting a TEMPORARY file system:" + error.name);
+    debug("Error occurred while requesting a TEMPORARY file system:" + error.name);
     finishJSTest();
 }
 
diff --git a/third_party/WebKit/LayoutTests/fast/filesystem/resources/simple-required-arguments-getmetadata.js b/third_party/WebKit/LayoutTests/fast/filesystem/resources/simple-required-arguments-getmetadata.js
index 9d9760b..5f9c385 100644
--- a/third_party/WebKit/LayoutTests/fast/filesystem/resources/simple-required-arguments-getmetadata.js
+++ b/third_party/WebKit/LayoutTests/fast/filesystem/resources/simple-required-arguments-getmetadata.js
@@ -9,7 +9,7 @@
 var fileSystem = null;
 
 function errorCallback(error) {
-    debug("Error occured while requesting a TEMPORARY file system:" + error.name);
+    debug("Error occurred while requesting a TEMPORARY file system:" + error.name);
     finishJSTest();
 }
 
diff --git a/third_party/WebKit/LayoutTests/fast/filesystem/resources/simple-required-arguments-remove.js b/third_party/WebKit/LayoutTests/fast/filesystem/resources/simple-required-arguments-remove.js
index d2a7ee09..9e1f8c3 100644
--- a/third_party/WebKit/LayoutTests/fast/filesystem/resources/simple-required-arguments-remove.js
+++ b/third_party/WebKit/LayoutTests/fast/filesystem/resources/simple-required-arguments-remove.js
@@ -9,7 +9,7 @@
 var fileSystem = null;
 
 function errorCallback(error) {
-    debug("Error occured while requesting a TEMPORARY file system:" + error.name);
+    debug("Error occurred while requesting a TEMPORARY file system:" + error.name);
     finishJSTest();
 }
 
diff --git a/third_party/WebKit/LayoutTests/fast/filesystem/resources/simple-temporary.js b/third_party/WebKit/LayoutTests/fast/filesystem/resources/simple-temporary.js
index f518580..8bb32c4 100644
--- a/third_party/WebKit/LayoutTests/fast/filesystem/resources/simple-temporary.js
+++ b/third_party/WebKit/LayoutTests/fast/filesystem/resources/simple-temporary.js
@@ -9,7 +9,7 @@
 var fileSystem = null;
 
 function errorCallback(error) {
-    debug('Error occured while requesting a TEMPORARY file system:' + error.name);
+    debug('Error occurred while requesting a TEMPORARY file system:' + error.name);
     finishJSTest();
 }
 
diff --git a/third_party/WebKit/LayoutTests/fast/filesystem/script-tests/flags-passing.js b/third_party/WebKit/LayoutTests/fast/filesystem/script-tests/flags-passing.js
index 0c0755f..29e6a34 100644
--- a/third_party/WebKit/LayoutTests/fast/filesystem/script-tests/flags-passing.js
+++ b/third_party/WebKit/LayoutTests/fast/filesystem/script-tests/flags-passing.js
@@ -28,7 +28,7 @@
 }
 
 function errorCallback(error) {
-    debug("Error occured during requesting Temporary FileSystem:" + error.name);
+    debug("Error occurred during requesting Temporary FileSystem:" + error.name);
     finishJSTest();
 }
 
diff --git a/third_party/WebKit/LayoutTests/fast/filesystem/script-tests/read-directory.js b/third_party/WebKit/LayoutTests/fast/filesystem/script-tests/read-directory.js
index 85b3c70..a3a3d6d 100644
--- a/third_party/WebKit/LayoutTests/fast/filesystem/script-tests/read-directory.js
+++ b/third_party/WebKit/LayoutTests/fast/filesystem/script-tests/read-directory.js
@@ -24,7 +24,7 @@
 
 function errorCallback(error)
 {
-    debug("Error occured:" + error.name);
+    debug("Error occurred:" + error.name);
     endTest();
 }
 
diff --git a/third_party/WebKit/LayoutTests/fast/filesystem/simple-readonly-file-object.html b/third_party/WebKit/LayoutTests/fast/filesystem/simple-readonly-file-object.html
index 961ff9b8..1a8dd7b 100644
--- a/third_party/WebKit/LayoutTests/fast/filesystem/simple-readonly-file-object.html
+++ b/third_party/WebKit/LayoutTests/fast/filesystem/simple-readonly-file-object.html
@@ -29,7 +29,7 @@
 }
 
 function errorCallback(error) {
-    testFailed("Error occured:" + error.name);
+    testFailed("Error occurred:" + error.name);
     finishJSTest();
 }
 
diff --git a/third_party/WebKit/LayoutTests/fast/forms/label/continous-click-on-label-expected.txt b/third_party/WebKit/LayoutTests/fast/forms/label/continous-click-on-label-expected.txt
index fe4feeb..fd90df6 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/label/continous-click-on-label-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/forms/label/continous-click-on-label-expected.txt
@@ -1,4 +1,4 @@
-Test the continous checking and unchecking of checkbox when clicking on associated label
+Test the continuous checking and unchecking of checkbox when clicking on associated label
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
diff --git a/third_party/WebKit/LayoutTests/fast/forms/label/continous-click-on-label.html b/third_party/WebKit/LayoutTests/fast/forms/label/continous-click-on-label.html
index 620fe4f..076814e 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/label/continous-click-on-label.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/label/continous-click-on-label.html
@@ -16,7 +16,7 @@
 <label><input type="checkbox" id="checkbox"><span id="span"></span></label>
 
 <script>
-description('Test the continous checking and unchecking of checkbox when ' +
+description('Test the continuous checking and unchecking of checkbox when ' +
     'clicking on associated label');
 
 var checkbox = document.getElementById('checkbox');
diff --git a/third_party/WebKit/LayoutTests/fast/forms/select-popup/popup-menu-key-operations.html b/third_party/WebKit/LayoutTests/fast/forms/select-popup/popup-menu-key-operations.html
index 237fbb9..26b08e0 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/select-popup/popup-menu-key-operations.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/select-popup/popup-menu-key-operations.html
@@ -105,7 +105,7 @@
     shouldBeEqualToString('menu.value', 'foo');
     shouldBeEqualToString('internals.selectMenuListText(menu)', 'bar');
 
-    // Blur should close the popup and select the provisonal item.
+    // Blur should close the popup and select the provisional item.
     menu.blur();
     shouldBeNull('window.internals.pagePopupWindow');
     shouldBeEqualToString('menu.value', 'bar');
diff --git a/third_party/WebKit/LayoutTests/fast/forms/select/option-mouseevents-expected.txt b/third_party/WebKit/LayoutTests/fast/forms/select/option-mouseevents-expected.txt
index af58070..f67aad9 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/select/option-mouseevents-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/forms/select/option-mouseevents-expected.txt
@@ -1,4 +1,4 @@
-This page tests whether a click event on a list box item propogates with the correct target and positioning values.
+This page tests whether a click event on a list box item propagates with the correct target and positioning values.
 Bug 3248: Mouse events on OPTION element seem to be ignored
 https://bugs.webkit.org/show_bug.cgi?id=3248
 
diff --git a/third_party/WebKit/LayoutTests/fast/forms/select/option-mouseevents.html b/third_party/WebKit/LayoutTests/fast/forms/select/option-mouseevents.html
index d54fd55..10e24f08 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/select/option-mouseevents.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/select/option-mouseevents.html
@@ -78,7 +78,7 @@
 </script>
 </head>
 <body onload="test();">
-<p>This page tests whether a click event on a list box item propogates with the correct target and positioning values.<br>
+<p>This page tests whether a click event on a list box item propagates with the correct target and positioning values.<br>
 Bug 3248: Mouse events on OPTION element seem to be ignored<br>
 <a href="https://bugs.webkit.org/show_bug.cgi?id=3248">https://bugs.webkit.org/show_bug.cgi?id=3248</a></p>
 <form action="" method="post">
diff --git a/third_party/WebKit/LayoutTests/fast/forms/select/select-width-font-change-expected.txt b/third_party/WebKit/LayoutTests/fast/forms/select/select-width-font-change-expected.txt
index 872ac6f..45d0da0 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/select/select-width-font-change-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/forms/select/select-width-font-change-expected.txt
@@ -1,4 +1,4 @@
-This test checks to see if changing the font of a select element causes it to resize to accomodate the larger text.
+This test checks to see if changing the font of a select element causes it to resize to accommodate the larger text.
 
 
 
diff --git a/third_party/WebKit/LayoutTests/fast/forms/select/select-width-font-change.html b/third_party/WebKit/LayoutTests/fast/forms/select/select-width-font-change.html
index a021d50..888a036 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/select/select-width-font-change.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/select/select-width-font-change.html
@@ -23,7 +23,7 @@
 
 <body onload="test()">
 
-<p>This test checks to see if changing the font of a select element causes it to resize to accomodate the larger text.</p>
+<p>This test checks to see if changing the font of a select element causes it to resize to accommodate the larger text.</p>
 
 <p><select id="select" style="font-size: 9px">
 <option>This is an option with some text in it.</option>
diff --git a/third_party/WebKit/LayoutTests/fast/forms/targeted-frame-submission.html b/third_party/WebKit/LayoutTests/fast/forms/targeted-frame-submission.html
index 4567547..6fd30c3 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/targeted-frame-submission.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/targeted-frame-submission.html
@@ -26,7 +26,7 @@
         <form action="resources/success.txt" method="GET" target="blankFrame">
             <input type="submit" value="form" id="blankButton">
         </form>
-        <div>This tests Targetted frame submission works.  If the test is successful, the text "SUCCESS" should be shown in the iframe below.</div>
+        <div>This tests Targeted frame submission works.  If the test is successful, the text "SUCCESS" should be shown in the iframe below.</div>
         <iframe src="about:blank" name="blankFrame" onload="subframeLoaded()"></iframe>
     </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/fast/forms/textarea/textarea-wrap-attribute-expected.txt b/third_party/WebKit/LayoutTests/fast/forms/textarea/textarea-wrap-attribute-expected.txt
index d690015..45558a3 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/textarea/textarea-wrap-attribute-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/forms/textarea/textarea-wrap-attribute-expected.txt
@@ -4,7 +4,7 @@
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-If wrap attribute is not specified it sould be empty String.
+If wrap attribute is not specified it should be empty String.
 PASS textArea.wrap is ''
 
 Check if it sets warpAttr value hard, should return hard.
diff --git a/third_party/WebKit/LayoutTests/fast/forms/textarea/textarea-wrap-attribute.html b/third_party/WebKit/LayoutTests/fast/forms/textarea/textarea-wrap-attribute.html
index f16c640..f72bb02b 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/textarea/textarea-wrap-attribute.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/textarea/textarea-wrap-attribute.html
@@ -13,7 +13,7 @@
 var textArea = document.createElement('textarea');
 document.body.appendChild(textArea);
 
-debug('If wrap attribute is not specified it sould be empty String.');
+debug('If wrap attribute is not specified it should be empty String.');
 shouldBe('textArea.wrap', "''");
 
 debug('');
diff --git a/third_party/WebKit/LayoutTests/fast/forms/textfield-to-password-on-focus.html b/third_party/WebKit/LayoutTests/fast/forms/textfield-to-password-on-focus.html
index 4cafb338..dae7f4b 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/textfield-to-password-on-focus.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/textfield-to-password-on-focus.html
@@ -19,7 +19,7 @@
         return;
     var field = document.getElementById("field").focus();
     // Need short delay because changing input type doesn't set selection in the
-    // input element immediately becasue layout is dirty.
+    // input element immediately because layout is dirty.
     setTimeout(function() {
         eventSender.keyDown("p");
         eventSender.keyDown("a");
diff --git a/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-step-attribute-expected.txt b/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-step-attribute-expected.txt
index c950433..ae3c716 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-step-attribute-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-step-attribute-expected.txt
@@ -1,4 +1,4 @@
-Check step attribute change causes apperance change
+Check step attribute change causes appearance change
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
diff --git a/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-step-attribute.html b/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-step-attribute.html
index 123f3786..bfb9fcaf 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-step-attribute.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-step-attribute.html
@@ -6,7 +6,7 @@
 <body>
 <input id=test type=time step=60>
 <script>
-description('Check step attribute change causes apperance change');
+description('Check step attribute change causes appearance change');
 var testInput = document.getElementById('test');
 var widthOfStep60 = testInput.offsetWidth;
 
diff --git a/third_party/WebKit/LayoutTests/fast/frames/sandboxed-iframe-attribute-parsing-03.html b/third_party/WebKit/LayoutTests/fast/frames/sandboxed-iframe-attribute-parsing-03.html
index e2f3764a..9984433 100644
--- a/third_party/WebKit/LayoutTests/fast/frames/sandboxed-iframe-attribute-parsing-03.html
+++ b/third_party/WebKit/LayoutTests/fast/frames/sandboxed-iframe-attribute-parsing-03.html
@@ -33,11 +33,11 @@
         In i hamnen vill jag styra,
         Därföre till godo tag
         Denna gång med tjugofyra.
-        
+
         'Kyssarna' ('The kisses'), Esaias Tegnér, 1782-1846
 
     allow-scripts allow-same-origin
-    
+
         int main(void)
         {
           return 0;
diff --git a/third_party/WebKit/LayoutTests/fast/frames/unique-name-all-subframes-have-same-name.html b/third_party/WebKit/LayoutTests/fast/frames/unique-name-all-subframes-have-same-name.html
index 128eb78..39c8db3 100644
--- a/third_party/WebKit/LayoutTests/fast/frames/unique-name-all-subframes-have-same-name.html
+++ b/third_party/WebKit/LayoutTests/fast/frames/unique-name-all-subframes-have-same-name.html
@@ -35,7 +35,7 @@
 in reality could conflict with other names.  This scenario is similar, but not
 the same as https://crbug.com/576969#c3.
 
-Additionaly, this test also exercises a scenario where the new
+Additionally, this test also exercises a scenario where the new
 FrameTree::generateLikelyUniqueSuffix can generate a suffix that
 is not really unique (and where uniquness comes from numberOfTries
 in FrameTree::ensureUniquenessOfUniqueName).
diff --git a/third_party/WebKit/LayoutTests/fast/hidpi/image-srcset-same-alternative-for-both-attributes-expected.txt b/third_party/WebKit/LayoutTests/fast/hidpi/image-srcset-same-alternative-for-both-attributes-expected.txt
index 05b4c4e..e6fcfab3 100644
--- a/third_party/WebKit/LayoutTests/fast/hidpi/image-srcset-same-alternative-for-both-attributes-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/hidpi/image-srcset-same-alternative-for-both-attributes-expected.txt
@@ -3,5 +3,5 @@
 TEST COMPLETE
 PASS internals.isPreloaded("resources/green-400-px-square.png") is false
 PASS document.getElementById("foo").clientWidth==100 is true
-This test passes if this img tag below is a blue square when the scale factor is 1. It ensures that when both source attributes has the same input alternative always the one from srcset is choosen
+This test passes if this img tag below is a blue square when the scale factor is 1. It ensures that when both source attributes has the same input alternative always the one from srcset is chosen
 
diff --git a/third_party/WebKit/LayoutTests/fast/hidpi/image-srcset-same-alternative-for-both-attributes.html b/third_party/WebKit/LayoutTests/fast/hidpi/image-srcset-same-alternative-for-both-attributes.html
index c763cf0c..c65e8f3 100644
--- a/third_party/WebKit/LayoutTests/fast/hidpi/image-srcset-same-alternative-for-both-attributes.html
+++ b/third_party/WebKit/LayoutTests/fast/hidpi/image-srcset-same-alternative-for-both-attributes.html
@@ -14,5 +14,5 @@
         shouldBeTrue('document.getElementById("foo").clientWidth==100');
     }, false);
 </script>
-<div>This test passes if this img tag below is a blue square when the scale factor is 1. It ensures that when both source attributes has the same input alternative always the one from srcset is choosen</div>
+<div>This test passes if this img tag below is a blue square when the scale factor is 1. It ensures that when both source attributes has the same input alternative always the one from srcset is chosen</div>
 <img id="foo" src="resources/green-400-px-square.png" srcset="resources/blue-100-px-square.png 1x">
diff --git a/third_party/WebKit/LayoutTests/fast/js/kde/resources/README b/third_party/WebKit/LayoutTests/fast/js/kde/resources/README
index f667066a..2cd374f 100644
--- a/third_party/WebKit/LayoutTests/fast/js/kde/resources/README
+++ b/third_party/WebKit/LayoutTests/fast/js/kde/resources/README
@@ -5,13 +5,13 @@
 This is a collection of JavaScript (aka ECMAScript) code snipplets
 used to test the KDE JavaScript library (dubbed kjs). Most of them
 once triggered a bug in the implementation of the
-interpreter. Allthough these bugs are probably fixed by now theses
+interpreter. Although these bugs are probably fixed by now theses
 tests can still be used for regression testing.
 
 NOTE:
 
 Don't confuse this code with the HTML bindings for the khtml
-widget. Those are implemented in a seperate module residing in
+widget. Those are implemented in a separate module residing in
 kdelibs/khtml/ecma. Test for those can be found elsewhere.
 
 USAGE:
diff --git a/third_party/WebKit/LayoutTests/fast/js/resources/image-preload-helper.js b/third_party/WebKit/LayoutTests/fast/js/resources/image-preload-helper.js
index b6fafdcc..4ac43ac9 100644
--- a/third_party/WebKit/LayoutTests/fast/js/resources/image-preload-helper.js
+++ b/third_party/WebKit/LayoutTests/fast/js/resources/image-preload-helper.js
@@ -1,7 +1,7 @@
 // This is used by several tests to help get images reliably preloaded.
 
 // Given a node, loads all urls specified in style declarations
-// attached to the node or it's decendants.
+// attached to the node or it's descendants.
 // imageCount specifies the number of images we expect to find (to try to add some
 // protection against brittleness due to imperfect url parsing, since other missing a preload
 // will typically result in a test that fails only occasionally).
diff --git a/third_party/WebKit/LayoutTests/fast/js/script-tests/date-DST-time-cusps.js b/third_party/WebKit/LayoutTests/fast/js/script-tests/date-DST-time-cusps.js
index 710945d..706052d 100644
--- a/third_party/WebKit/LayoutTests/fast/js/script-tests/date-DST-time-cusps.js
+++ b/third_party/WebKit/LayoutTests/fast/js/script-tests/date-DST-time-cusps.js
@@ -7,7 +7,7 @@
 );
 
 description(
-"For times that happen twice the behavior of all major browsers seems to be to pick the second occurance, i.e. Standard Time not Daylight Time"
+"For times that happen twice the behavior of all major browsers seems to be to pick the second occurrence, i.e. Standard Time not Daylight Time"
 );
 
 var testCases = [];
diff --git a/third_party/WebKit/LayoutTests/fast/js/script-tests/method-check.js b/third_party/WebKit/LayoutTests/fast/js/script-tests/method-check.js
index c1ca3bd7..1911216 100644
--- a/third_party/WebKit/LayoutTests/fast/js/script-tests/method-check.js
+++ b/third_party/WebKit/LayoutTests/fast/js/script-tests/method-check.js
@@ -14,7 +14,7 @@
         GCController.collect();
     else {
         // The following 3 lines cause gc() flush on a Debian
-        // Linux machine, but there is no garantee, it works on
+        // Linux machine, but there is no guarantee, it works on
         // any other computer. (Not even another Debian Linux)
         // If func2() is not called or a much bigger or lower
         // value than 5000 is chosen, the crash won't happen
diff --git a/third_party/WebKit/LayoutTests/fast/js/script-tests/reparsing-semicolon-insertion.js b/third_party/WebKit/LayoutTests/fast/js/script-tests/reparsing-semicolon-insertion.js
index f6a606dc..380a96a 100644
--- a/third_party/WebKit/LayoutTests/fast/js/script-tests/reparsing-semicolon-insertion.js
+++ b/third_party/WebKit/LayoutTests/fast/js/script-tests/reparsing-semicolon-insertion.js
@@ -8,7 +8,7 @@
 // this test can simply be changed to reflect that.
 
 // It is important that the closing braces be on the same line as the commas, so
-// that a newline doesn't act as a terminator when lexing inbetween.
+// that a newline doesn't act as a terminator when lexing in between.
 
 function commaTest() { a = 1 }
 
diff --git a/third_party/WebKit/LayoutTests/fast/js/throw-from-array-sort.html b/third_party/WebKit/LayoutTests/fast/js/throw-from-array-sort.html
index a78b742..0dc52e0 100644
--- a/third_party/WebKit/LayoutTests/fast/js/throw-from-array-sort.html
+++ b/third_party/WebKit/LayoutTests/fast/js/throw-from-array-sort.html
@@ -1,7 +1,7 @@
 <p>This test verifies that an exception thrown during array sort immediately ends execution.</p>
 <p>If the test passes, you'll see a pass message below.</p>
 
-<pre id="console">FAIL: Exception did not propogate from array sort.</pre>
+<pre id="console">FAIL: Exception did not propagate from array sort.</pre>
 
 <script>
 function log(s)
diff --git a/third_party/WebKit/LayoutTests/fast/replaced/max-width-percent.html b/third_party/WebKit/LayoutTests/fast/replaced/max-width-percent.html
index 07bd28d..7caf4c3 100644
--- a/third_party/WebKit/LayoutTests/fast/replaced/max-width-percent.html
+++ b/third_party/WebKit/LayoutTests/fast/replaced/max-width-percent.html
@@ -2,7 +2,7 @@
 <script>
     function test()
     {
-        // Force intial layout
+        // Force initial layout
         document.body.offsetTop;
 
         // Force preferred width recalculation
diff --git a/third_party/WebKit/LayoutTests/fast/scrolling/editor-command-scroll-page-scale.html b/third_party/WebKit/LayoutTests/fast/scrolling/editor-command-scroll-page-scale.html
index 3da76c78..5caea80 100644
--- a/third_party/WebKit/LayoutTests/fast/scrolling/editor-command-scroll-page-scale.html
+++ b/third_party/WebKit/LayoutTests/fast/scrolling/editor-command-scroll-page-scale.html
@@ -11,7 +11,7 @@
     internals.setPageScaleFactor(2);
   }
 
-  // Test Document scroll seperately so we ensure it scrolls all the way in one
+  // Test Document scroll separately so we ensure it scrolls all the way in one
   // shot.
   function testDocumentScroll() {
     internals.executeCommand(document, 'ScrollToEndOfDocument', '');
diff --git a/third_party/WebKit/LayoutTests/fast/shapes/shape-outside-floats/shape-outside-polygon-015.html b/third_party/WebKit/LayoutTests/fast/shapes/shape-outside-floats/shape-outside-polygon-015.html
index 349c59b2..746139c8 100644
--- a/third_party/WebKit/LayoutTests/fast/shapes/shape-outside-floats/shape-outside-polygon-015.html
+++ b/third_party/WebKit/LayoutTests/fast/shapes/shape-outside-floats/shape-outside-polygon-015.html
@@ -11,7 +11,7 @@
         <meta name="flags" content="ahem" />
         <meta name="assert" content="The test verifies that text wraps around a
                                      right float with a shape-outside defined as
-                                     an polygon from the content box wtih a shape margin.">
+                                     an polygon from the content box with a shape margin.">
     </head>
     <style>
         body {
diff --git a/third_party/WebKit/LayoutTests/fast/speechsynthesis/speech-synthesis-speak-expected.txt b/third_party/WebKit/LayoutTests/fast/speechsynthesis/speech-synthesis-speak-expected.txt
index e3a49ab..69b4f6b 100644
--- a/third_party/WebKit/LayoutTests/fast/speechsynthesis/speech-synthesis-speak-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/speechsynthesis/speech-synthesis-speak-expected.txt
@@ -1,4 +1,4 @@
-This tests that the basic mechanisms of speaking text work, including sending the job and receving the callback.
+This tests that the basic mechanisms of speaking text work, including sending the job and receiving the callback.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
diff --git a/third_party/WebKit/LayoutTests/fast/speechsynthesis/speech-synthesis-speak.html b/third_party/WebKit/LayoutTests/fast/speechsynthesis/speech-synthesis-speak.html
index ff47322..dfb993e 100644
--- a/third_party/WebKit/LayoutTests/fast/speechsynthesis/speech-synthesis-speak.html
+++ b/third_party/WebKit/LayoutTests/fast/speechsynthesis/speech-synthesis-speak.html
@@ -12,7 +12,7 @@
     if (window.internals)
         window.internals.enableMockSpeechSynthesizer(window);
 
-    description("This tests that the basic mechanisms of speaking text work, including sending the job and receving the callback.");
+    description("This tests that the basic mechanisms of speaking text work, including sending the job and receiving the callback.");
 
     if (window.testRunner)
         testRunner.waitUntilDone();
diff --git a/third_party/WebKit/LayoutTests/fast/url/invalid-urls-utf8.html b/third_party/WebKit/LayoutTests/fast/url/invalid-urls-utf8.html
index 85cae77..7ac194ad 100644
--- a/third_party/WebKit/LayoutTests/fast/url/invalid-urls-utf8.html
+++ b/third_party/WebKit/LayoutTests/fast/url/invalid-urls-utf8.html
@@ -14,7 +14,7 @@
 
 // Those are all invalid URLs. They should not be partially modified by the parser.
 var testSet = [
-    // Empty Authority for a standard hierachical URL.
+    // Empty Authority for a standard hierarchical URL.
     'http:///',
     'https:///',
     'ftp:///',
diff --git a/third_party/WebKit/LayoutTests/fast/url/script-tests/file-http-base.js b/third_party/WebKit/LayoutTests/fast/url/script-tests/file-http-base.js
index 7a4d686f..1c12b2b 100644
--- a/third_party/WebKit/LayoutTests/fast/url/script-tests/file-http-base.js
+++ b/third_party/WebKit/LayoutTests/fast/url/script-tests/file-http-base.js
@@ -7,7 +7,7 @@
     ["file:", "file:///"],
     ["file:UNChost/path", "file://unchost/path"],
     // CanonicalizeFileURL supports absolute Windows style paths for IE
-    // compatability. Note that the caller must decide that this is a file
+    // compatibility. Note that the caller must decide that this is a file
     // URL itself so it can call the file canonicalizer. This is usually
     // done automatically as part of relative URL resolving.
     ["c:\\\\foo\\\\bar", "file:///C:/foo/bar"],
@@ -18,7 +18,7 @@
     ["\\\\\\\\server\\\\file", "file://server/file"],
     ["/\\\\server/file", "file://server/file"],
     // We should preserve the number of slashes after the colon for IE
-    // compatability, except when there is none, in which case we should
+    // compatibility, except when there is none, in which case we should
     // add one.
     ["file:c:foo/bar.html", "file:///C:/foo/bar.html"],
     ["file:/\\\\/\\\\C:\\\\\\\\//foo\\\\bar.html", "file:///C:////foo/bar.html"],
diff --git a/third_party/WebKit/LayoutTests/fast/url/script-tests/file.js b/third_party/WebKit/LayoutTests/fast/url/script-tests/file.js
index bc13e065..5eead48 100644
--- a/third_party/WebKit/LayoutTests/fast/url/script-tests/file.js
+++ b/third_party/WebKit/LayoutTests/fast/url/script-tests/file.js
@@ -7,7 +7,7 @@
     ["file:", "file:///"],
     ["file:UNChost/path", "file://unchost/path"],
     // CanonicalizeFileURL supports absolute Windows style paths for IE
-    // compatability. Note that the caller must decide that this is a file
+    // compatibility. Note that the caller must decide that this is a file
     // URL itself so it can call the file canonicalizer. This is usually
     // done automatically as part of relative URL resolving.
     ["c:\\\\foo\\\\bar", "file:///C:/foo/bar"],
@@ -18,7 +18,7 @@
     ["\\\\\\\\server\\\\file", "file://server/file"],
     ["/\\\\server/file", "file://server/file"],
     // We should preserve the number of slashes after the colon for IE
-    // compatability, except when there is none, in which case we should
+    // compatibility, except when there is none, in which case we should
     // add one.
     ["file:c:foo/bar.html", "file:///C:/foo/bar.html"],
     ["file:/\\\\/\\\\C:\\\\\\\\//foo\\\\bar.html", "file:///C:////foo/bar.html"],
diff --git a/third_party/WebKit/LayoutTests/fast/xsl/mozilla-tests.xsl b/third_party/WebKit/LayoutTests/fast/xsl/mozilla-tests.xsl
index b10646d..ee5306aa 100644
--- a/third_party/WebKit/LayoutTests/fast/xsl/mozilla-tests.xsl
+++ b/third_party/WebKit/LayoutTests/fast/xsl/mozilla-tests.xsl
@@ -69,7 +69,7 @@
 <!-- empty variable for named template test -->
 <xsl:variable name="dummy-param" />
 
-<!-- supress non-selected nodes-->
+<!-- suppress non-selected nodes-->
 <xsl:template match="*"/>
 
 <!-- variable tests -->
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/sources/inline-module-export-error-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector/sources/inline-module-export-error-expected.txt
new file mode 100644
index 0000000..1390045
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/sources/inline-module-export-error-expected.txt
@@ -0,0 +1,8 @@
+CONSOLE ERROR: line 5: Uncaught SyntaxError: The requested module does not provide an export named 'x'
+CONSOLE ERROR: line 5: Uncaught SyntaxError: The requested module does not provide an export named 'x'
+Tests lineNumber for import error inside of inline module.
+
+Script execution paused.
+line 4, content: <script type="module">
+Script execution resumed.
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/sources/inline-module-export-error.html b/third_party/WebKit/LayoutTests/http/tests/inspector/sources/inline-module-export-error.html
new file mode 100644
index 0000000..90148ef609
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/sources/inline-module-export-error.html
@@ -0,0 +1,44 @@
+<html>
+<head>
+<script src="../inspector-test.js"></script>
+<script src="../debugger-test.js"></script>
+<script type="module">
+import {x} from "./resources/empty-module.js";
+</script>
+<script>
+
+var test = function()
+{
+    InspectorTest.startDebuggerTest(step1);
+
+    function step1()
+    {
+        InspectorTest.DebuggerAgent.setPauseOnExceptions(SDK.DebuggerModel.PauseOnExceptionsState.PauseOnAllExceptions);
+        InspectorTest.waitUntilPaused(step2);
+        InspectorTest.reloadPage();
+    }
+
+    function step2()
+    {
+        var callFrames = InspectorTest.debuggerModel.callFrames;
+        var frame = callFrames[0];
+        var uiLocation = Bindings.debuggerWorkspaceBinding.rawLocationToUILocation(frame.location());
+        InspectorTest.showUISourceCode(uiLocation.uiSourceCode, dumpCallFrameLine);
+
+        function dumpCallFrameLine(sourceFrame)
+        {
+            var resourceText = sourceFrame._textEditor.text();
+            var lines = resourceText.split("\n");
+            var lineNumber = uiLocation.lineNumber;
+            InspectorTest.addResult("line " + lineNumber + ", content: " + lines[lineNumber]);
+            InspectorTest.completeDebuggerTest();
+        }
+    }
+}
+
+</script>
+</head>
+<body onload="runTest()">
+<p>Tests lineNumber for import error inside of inline module.</p>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/sources/resources/empty-module.js b/third_party/WebKit/LayoutTests/http/tests/inspector/sources/resources/empty-module.js
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/sources/resources/empty-module.js
diff --git a/third_party/WebKit/LayoutTests/platform/linux/css3/blending/background-blend-mode-image-image-expected.png b/third_party/WebKit/LayoutTests/platform/linux/css3/blending/background-blend-mode-image-image-expected.png
new file mode 100644
index 0000000..44f46896
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/css3/blending/background-blend-mode-image-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/css3/blending/background-blend-mode-image-svg-expected.png b/third_party/WebKit/LayoutTests/platform/linux/css3/blending/background-blend-mode-image-svg-expected.png
new file mode 100644
index 0000000..e12a82d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/css3/blending/background-blend-mode-image-svg-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/css3/blending/background-blend-mode-multiple-background-layers-expected.png b/third_party/WebKit/LayoutTests/platform/linux/css3/blending/background-blend-mode-multiple-background-layers-expected.png
new file mode 100644
index 0000000..0e12068
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/css3/blending/background-blend-mode-multiple-background-layers-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/css3/blending/background-blend-mode-tiled-gradient-expected.png b/third_party/WebKit/LayoutTests/platform/linux/css3/blending/background-blend-mode-tiled-gradient-expected.png
new file mode 100644
index 0000000..3b75e0b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/css3/blending/background-blend-mode-tiled-gradient-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/canvas/canvas-composite-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/canvas/canvas-composite-shadow-expected.png
index 8b21aab..974e5ad4 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/canvas/canvas-composite-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/canvas/canvas-composite-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/targeted-frame-submission-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/targeted-frame-submission-expected.png
index 1477d68..a144de2 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/targeted-frame-submission-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/targeted-frame-submission-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/targeted-frame-submission-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/targeted-frame-submission-expected.txt
index 6926e30..615198a1 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/targeted-frame-submission-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/targeted-frame-submission-expected.txt
@@ -10,9 +10,9 @@
               text run at (0,0) width 26: "form"
         LayoutText {#text} at (0,0) size 0x0
       LayoutBlockFlow {DIV} at (0,38) size 784x40
-        LayoutText {#text} at (0,0) size 764x39
-          text run at (0,0) width 287: "This tests Targetted frame submission works. "
-          text run at (286,0) width 478: "If the test is successful, the text \"SUCCESS\" should be shown in the iframe"
+        LayoutText {#text} at (0,0) size 760x39
+          text run at (0,0) width 283: "This tests Targeted frame submission works. "
+          text run at (282,0) width 478: "If the test is successful, the text \"SUCCESS\" should be shown in the iframe"
           text run at (0,20) width 42: "below."
       LayoutBlockFlow (anonymous) at (0,78) size 784x154
         LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-shadow-expected.png
index 8b21aab..974e5ad4 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/targeted-frame-submission-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/targeted-frame-submission-expected.png
index 3f82814..4db7f87 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/targeted-frame-submission-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/targeted-frame-submission-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/targeted-frame-submission-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/targeted-frame-submission-expected.txt
index e43f8bb..2837361 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/targeted-frame-submission-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/targeted-frame-submission-expected.txt
@@ -10,9 +10,9 @@
               text run at (0,0) width 23: "form"
         LayoutText {#text} at (0,0) size 0x0
       LayoutBlockFlow {DIV} at (0,34) size 784x36
-        LayoutText {#text} at (0,0) size 778x36
-          text run at (0,0) width 294: "This tests Targetted frame submission works. "
-          text run at (293,0) width 485: "If the test is successful, the text \"SUCCESS\" should be shown in the iframe"
+        LayoutText {#text} at (0,0) size 773x36
+          text run at (0,0) width 289: "This tests Targeted frame submission works. "
+          text run at (288,0) width 485: "If the test is successful, the text \"SUCCESS\" should be shown in the iframe"
           text run at (0,18) width 43: "below."
       LayoutBlockFlow (anonymous) at (0,70) size 784x154
         LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/forms/targeted-frame-submission-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/forms/targeted-frame-submission-expected.png
index cd68c570..0b9be49 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/forms/targeted-frame-submission-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/forms/targeted-frame-submission-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/forms/targeted-frame-submission-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/forms/targeted-frame-submission-expected.txt
index 564aad6..05370642 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/forms/targeted-frame-submission-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/forms/targeted-frame-submission-expected.txt
@@ -10,9 +10,9 @@
               text run at (0,0) width 25: "form"
         LayoutText {#text} at (0,0) size 0x0
       LayoutBlockFlow {DIV} at (0,34) size 784x36
-        LayoutText {#text} at (0,0) size 778x36
-          text run at (0,0) width 294: "This tests Targetted frame submission works. "
-          text run at (293,0) width 485: "If the test is successful, the text \"SUCCESS\" should be shown in the iframe"
+        LayoutText {#text} at (0,0) size 773x36
+          text run at (0,0) width 289: "This tests Targeted frame submission works. "
+          text run at (288,0) width 485: "If the test is successful, the text \"SUCCESS\" should be shown in the iframe"
           text run at (0,18) width 43: "below."
       LayoutBlockFlow (anonymous) at (0,70) size 784x154
         LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/forms/targeted-frame-submission-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/forms/targeted-frame-submission-expected.png
index d28bd47..f279a82b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/forms/targeted-frame-submission-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/forms/targeted-frame-submission-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/forms/targeted-frame-submission-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/forms/targeted-frame-submission-expected.txt
index 2150af3..315fd956 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/forms/targeted-frame-submission-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/forms/targeted-frame-submission-expected.txt
@@ -10,9 +10,9 @@
               text run at (0,0) width 26: "form"
         LayoutText {#text} at (0,0) size 0x0
       LayoutBlockFlow {DIV} at (0,34) size 784x36
-        LayoutText {#text} at (0,0) size 778x36
-          text run at (0,0) width 294: "This tests Targetted frame submission works. "
-          text run at (293,0) width 485: "If the test is successful, the text \"SUCCESS\" should be shown in the iframe"
+        LayoutText {#text} at (0,0) size 773x36
+          text run at (0,0) width 289: "This tests Targeted frame submission works. "
+          text run at (288,0) width 485: "If the test is successful, the text \"SUCCESS\" should be shown in the iframe"
           text run at (0,18) width 43: "below."
       LayoutBlockFlow (anonymous) at (0,70) size 784x154
         LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/css3/blending/background-blend-mode-gif-color-2-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/css3/blending/background-blend-mode-gif-color-2-expected.png
new file mode 100644
index 0000000..3126f0c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-retina/css3/blending/background-blend-mode-gif-color-2-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/targeted-frame-submission-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/targeted-frame-submission-expected.png
index cd68c570..0b9be49 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/targeted-frame-submission-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/targeted-frame-submission-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/targeted-frame-submission-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/targeted-frame-submission-expected.txt
index 564aad6..05370642 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/targeted-frame-submission-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/targeted-frame-submission-expected.txt
@@ -10,9 +10,9 @@
               text run at (0,0) width 25: "form"
         LayoutText {#text} at (0,0) size 0x0
       LayoutBlockFlow {DIV} at (0,34) size 784x36
-        LayoutText {#text} at (0,0) size 778x36
-          text run at (0,0) width 294: "This tests Targetted frame submission works. "
-          text run at (293,0) width 485: "If the test is successful, the text \"SUCCESS\" should be shown in the iframe"
+        LayoutText {#text} at (0,0) size 773x36
+          text run at (0,0) width 289: "This tests Targeted frame submission works. "
+          text run at (288,0) width 485: "If the test is successful, the text \"SUCCESS\" should be shown in the iframe"
           text run at (0,18) width 43: "below."
       LayoutBlockFlow (anonymous) at (0,70) size 784x154
         LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-gradient-image-expected.png b/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-gradient-image-expected.png
index 3587378..a67ca3ca 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-gradient-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-gradient-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-image-color-expected.png b/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-image-color-expected.png
index 68726da4..3700c85 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-image-color-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-image-color-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-image-image-expected.png b/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-image-image-expected.png
index 9b98e8f..3912980 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-image-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-image-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-image-svg-expected.png b/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-image-svg-expected.png
index 17bc301..52dfa2a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-image-svg-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-image-svg-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-multiple-background-layers-expected.png b/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-multiple-background-layers-expected.png
index 78123092..fe8c7fe 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-multiple-background-layers-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-multiple-background-layers-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-tiled-gradient-expected.png b/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-tiled-gradient-expected.png
index 9c7f54d3..a22d439 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-tiled-gradient-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-tiled-gradient-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/effect-background-blend-mode-expected.png b/third_party/WebKit/LayoutTests/platform/mac/css3/blending/effect-background-blend-mode-expected.png
index 278fd3ab..a37f843 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/effect-background-blend-mode-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/css3/blending/effect-background-blend-mode-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/effect-background-blend-mode-tiled-expected.png b/third_party/WebKit/LayoutTests/platform/mac/css3/blending/effect-background-blend-mode-tiled-expected.png
index 531ad81c..0575fe2 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/effect-background-blend-mode-tiled-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/css3/blending/effect-background-blend-mode-tiled-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/canvas/canvas-composite-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/canvas/canvas-composite-shadow-expected.png
index 21ce7a8..aa210c69 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/canvas/canvas-composite-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/canvas/canvas-composite-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/targeted-frame-submission-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/targeted-frame-submission-expected.png
index 37caf066..48055aeb 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/targeted-frame-submission-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/targeted-frame-submission-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/targeted-frame-submission-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/targeted-frame-submission-expected.txt
index a248d33..d03c1f93 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/targeted-frame-submission-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/targeted-frame-submission-expected.txt
@@ -10,9 +10,9 @@
               text run at (0,0) width 25: "form"
         LayoutText {#text} at (0,0) size 0x0
       LayoutBlockFlow {DIV} at (0,34) size 784x36
-        LayoutText {#text} at (0,0) size 778x36
-          text run at (0,0) width 294: "This tests Targetted frame submission works. "
-          text run at (293,0) width 485: "If the test is successful, the text \"SUCCESS\" should be shown in the iframe"
+        LayoutText {#text} at (0,0) size 773x36
+          text run at (0,0) width 289: "This tests Targeted frame submission works. "
+          text run at (288,0) width 485: "If the test is successful, the text \"SUCCESS\" should be shown in the iframe"
           text run at (0,18) width 43: "below."
       LayoutBlockFlow (anonymous) at (0,70) size 784x154
         LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-shadow-expected.png
index 21ce7a8..aa210c69 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-gradient-image-expected.png b/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-gradient-image-expected.png
index 34bd34a..39b584c5 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-gradient-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-gradient-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-image-color-expected.png b/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-image-color-expected.png
index b3a801c..43c99f64 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-image-color-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-image-color-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-image-image-expected.png b/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-image-image-expected.png
index 8c4b4e3..67dacf44 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-image-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-image-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-image-svg-expected.png b/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-image-svg-expected.png
index a9ed133..e917b24 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-image-svg-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-image-svg-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-multiple-background-layers-expected.png b/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-multiple-background-layers-expected.png
index 5c663f5c..a8659ea 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-multiple-background-layers-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-multiple-background-layers-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-tiled-gradient-expected.png b/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-tiled-gradient-expected.png
index 7d25cb1..25ce7cf 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-tiled-gradient-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/css3/blending/background-blend-mode-tiled-gradient-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/css3/blending/effect-background-blend-mode-expected.png b/third_party/WebKit/LayoutTests/platform/win/css3/blending/effect-background-blend-mode-expected.png
index 701c6c6..cb4f20a4 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css3/blending/effect-background-blend-mode-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/css3/blending/effect-background-blend-mode-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/css3/blending/effect-background-blend-mode-tiled-expected.png b/third_party/WebKit/LayoutTests/platform/win/css3/blending/effect-background-blend-mode-tiled-expected.png
index e6481a5..7017949 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css3/blending/effect-background-blend-mode-tiled-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/css3/blending/effect-background-blend-mode-tiled-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-composite-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-composite-shadow-expected.png
index 801b131..e30901b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-composite-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-composite-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/select/option-mouseevents-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/forms/select/option-mouseevents-expected.txt
index a523d04..8eb0db8ab 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/select/option-mouseevents-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/select/option-mouseevents-expected.txt
@@ -1,4 +1,4 @@
-This page tests whether a click event on a list box item propogates with the correct target and positioning values.
+This page tests whether a click event on a list box item propagates with the correct target and positioning values.
 Bug 3248: Mouse events on OPTION element seem to be ignored
 https://bugs.webkit.org/show_bug.cgi?id=3248
 
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/targeted-frame-submission-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/targeted-frame-submission-expected.png
index b43e10a..60306c4 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/targeted-frame-submission-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/targeted-frame-submission-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/targeted-frame-submission-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/forms/targeted-frame-submission-expected.txt
index bef9d96..408543a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/targeted-frame-submission-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/targeted-frame-submission-expected.txt
@@ -10,9 +10,9 @@
               text run at (0,0) width 25: "form"
         LayoutText {#text} at (0,0) size 0x0
       LayoutBlockFlow {DIV} at (0,38) size 784x20
-        LayoutText {#text} at (0,0) size 768x19
-          text run at (0,0) width 274: "This tests Targetted frame submission works. "
-          text run at (273,0) width 495: "If the test is successful, the text \"SUCCESS\" should be shown in the iframe below."
+        LayoutText {#text} at (0,0) size 764x19
+          text run at (0,0) width 270: "This tests Targeted frame submission works. "
+          text run at (269,0) width 495: "If the test is successful, the text \"SUCCESS\" should be shown in the iframe below."
       LayoutBlockFlow (anonymous) at (0,58) size 784x154
         LayoutText {#text} at (0,0) size 0x0
 layer at (8,66) size 304x154
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-shadow-expected.png
index 801b131..e30901b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/resources/testharness.js b/third_party/WebKit/LayoutTests/resources/testharness.js
index 73913d6..a0ec94d 100644
--- a/third_party/WebKit/LayoutTests/resources/testharness.js
+++ b/third_party/WebKit/LayoutTests/resources/testharness.js
@@ -591,7 +591,7 @@
 
         /**
          * Returns a Promise that will resolve after the specified event or
-         * series of events has occured.
+         * series of events has occurred.
          */
         this.wait_for = function(types) {
             if (waitingFor) {
@@ -971,7 +971,7 @@
     function assert_approx_equals(actual, expected, epsilon, description)
     {
         /*
-         * Test if two primitive numbers are equal withing +/- epsilon
+         * Test if two primitive numbers are equal within +/- epsilon
          */
         assert(typeof actual === "number",
                "assert_approx_equals", description,
diff --git a/third_party/WebKit/LayoutTests/resources/testharnessreport.js b/third_party/WebKit/LayoutTests/resources/testharnessreport.js
index 3c4fa649..1d3d729 100644
--- a/third_party/WebKit/LayoutTests/resources/testharnessreport.js
+++ b/third_party/WebKit/LayoutTests/resources/testharnessreport.js
@@ -119,7 +119,8 @@
         } else if (pathAndBase.startsWith('/pointerevents/')
                    || pathAndBase.startsWith('/uievents/')
                    || pathAndBase.startsWith('/pointerlock/')
-                   || pathAndBase.startsWith('/html/')) {
+                   || pathAndBase.startsWith('/html/')
+                   || pathAndBase.startsWith('/input-events/')) {
             // Per-test automation scripts.
             src = automationPath + pathAndBase + '-automation.js';
         } else {
diff --git a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt
index c884929..e1cd15e4f 100644
--- a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt
@@ -38,6 +38,7 @@
     getter orientation
     getter placeholder
     getter posInSet
+    getter pressed
     getter readOnly
     getter relevant
     getter required
@@ -76,6 +77,7 @@
     setter orientation
     setter placeholder
     setter posInSet
+    setter pressed
     setter readOnly
     setter relevant
     setter required
@@ -2741,6 +2743,7 @@
     getter x
     getter y
     method constructor
+    method decode
     setter align
     setter alt
     setter border
@@ -3757,6 +3760,7 @@
     getter x
     getter y
     method constructor
+    method decode
     setter align
     setter alt
     setter border
diff --git a/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt
index cf2c5cf5..2f11f82 100644
--- a/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt
@@ -586,6 +586,7 @@
     property complete
     property crossOrigin
     property currentSrc
+    property decode
     property height
     property hspace
     property isMap
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index f852486..72f8097 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -38,6 +38,7 @@
     getter orientation
     getter placeholder
     getter posInSet
+    getter pressed
     getter readOnly
     getter relevant
     getter required
@@ -76,6 +77,7 @@
     setter orientation
     setter placeholder
     setter posInSet
+    setter pressed
     setter readOnly
     setter relevant
     setter required
@@ -2741,6 +2743,7 @@
     getter x
     getter y
     method constructor
+    method decode
     setter align
     setter alt
     setter border
@@ -3757,6 +3760,7 @@
     getter x
     getter y
     method constructor
+    method decode
     setter align
     setter alt
     setter border
diff --git a/third_party/WebKit/Source/bindings/core/v8/BUILD.gn b/third_party/WebKit/Source/bindings/core/v8/BUILD.gn
index b8a25c6..6708cbef 100644
--- a/third_party/WebKit/Source/bindings/core/v8/BUILD.gn
+++ b/third_party/WebKit/Source/bindings/core/v8/BUILD.gn
@@ -10,6 +10,165 @@
 
 visibility = [ "//third_party/WebKit/Source/*" ]
 
+generated_core_dictionary_files = [
+  "$blink_core_output_dir/animation/AnimationEffectTimingProperties.cpp",
+  "$blink_core_output_dir/animation/AnimationEffectTimingProperties.h",
+  "$blink_core_output_dir/animation/ComputedTimingProperties.cpp",
+  "$blink_core_output_dir/animation/ComputedTimingProperties.h",
+  "$blink_core_output_dir/animation/KeyframeAnimationOptions.cpp",
+  "$blink_core_output_dir/animation/KeyframeAnimationOptions.h",
+  "$blink_core_output_dir/animation/KeyframeEffectOptions.cpp",
+  "$blink_core_output_dir/animation/KeyframeEffectOptions.h",
+  "$blink_core_output_dir/css/FontFaceDescriptors.cpp",
+  "$blink_core_output_dir/css/FontFaceDescriptors.h",
+  "$blink_core_output_dir/css/FontFaceSetLoadEventInit.cpp",
+  "$blink_core_output_dir/css/FontFaceSetLoadEventInit.h",
+  "$blink_core_output_dir/css/MediaQueryListEventInit.cpp",
+  "$blink_core_output_dir/css/MediaQueryListEventInit.h",
+  "$blink_core_output_dir/css/PropertyDescriptor.cpp",
+  "$blink_core_output_dir/css/PropertyDescriptor.h",
+  "$blink_core_output_dir/css/cssom/CSSCalcDictionary.cpp",
+  "$blink_core_output_dir/css/cssom/CSSCalcDictionary.h",
+  "$blink_core_output_dir/dom/ElementCreationOptions.cpp",
+  "$blink_core_output_dir/dom/ElementCreationOptions.h",
+  "$blink_core_output_dir/dom/ElementDefinitionOptions.cpp",
+  "$blink_core_output_dir/dom/ElementDefinitionOptions.h",
+  "$blink_core_output_dir/dom/ElementRegistrationOptions.cpp",
+  "$blink_core_output_dir/dom/ElementRegistrationOptions.h",
+  "$blink_core_output_dir/dom/GetRootNodeOptions.cpp",
+  "$blink_core_output_dir/dom/GetRootNodeOptions.h",
+  "$blink_core_output_dir/dom/IdleRequestOptions.cpp",
+  "$blink_core_output_dir/dom/IdleRequestOptions.h",
+  "$blink_core_output_dir/dom/IntersectionObserverInit.cpp",
+  "$blink_core_output_dir/dom/IntersectionObserverInit.h",
+  "$blink_core_output_dir/dom/MutationObserverInit.cpp",
+  "$blink_core_output_dir/dom/MutationObserverInit.h",
+  "$blink_core_output_dir/dom/shadow/ShadowRootInit.cpp",
+  "$blink_core_output_dir/dom/shadow/ShadowRootInit.h",
+  "$blink_core_output_dir/dom/TouchInit.cpp",
+  "$blink_core_output_dir/dom/TouchInit.h",
+  "$blink_core_output_dir/events/AddEventListenerOptions.cpp",
+  "$blink_core_output_dir/events/AddEventListenerOptions.h",
+  "$blink_core_output_dir/events/AnimationEventInit.cpp",
+  "$blink_core_output_dir/events/AnimationEventInit.h",
+  "$blink_core_output_dir/events/AnimationPlaybackEventInit.cpp",
+  "$blink_core_output_dir/events/AnimationPlaybackEventInit.h",
+  "$blink_core_output_dir/events/ApplicationCacheErrorEventInit.cpp",
+  "$blink_core_output_dir/events/ApplicationCacheErrorEventInit.h",
+  "$blink_core_output_dir/events/ClipboardEventInit.cpp",
+  "$blink_core_output_dir/events/ClipboardEventInit.h",
+  "$blink_core_output_dir/events/CompositionEventInit.cpp",
+  "$blink_core_output_dir/events/CompositionEventInit.h",
+  "$blink_core_output_dir/events/CustomEventInit.cpp",
+  "$blink_core_output_dir/events/CustomEventInit.h",
+  "$blink_core_output_dir/events/DragEventInit.cpp",
+  "$blink_core_output_dir/events/DragEventInit.h",
+  "$blink_core_output_dir/events/ErrorEventInit.cpp",
+  "$blink_core_output_dir/events/ErrorEventInit.h",
+  "$blink_core_output_dir/events/EventInit.cpp",
+  "$blink_core_output_dir/events/EventInit.h",
+  "$blink_core_output_dir/events/EventListenerOptions.cpp",
+  "$blink_core_output_dir/events/EventListenerOptions.h",
+  "$blink_core_output_dir/events/EventModifierInit.cpp",
+  "$blink_core_output_dir/events/EventModifierInit.h",
+  "$blink_core_output_dir/events/FocusEventInit.cpp",
+  "$blink_core_output_dir/events/FocusEventInit.h",
+  "$blink_core_output_dir/events/HashChangeEventInit.cpp",
+  "$blink_core_output_dir/events/HashChangeEventInit.h",
+  "$blink_core_output_dir/events/InputEventInit.cpp",
+  "$blink_core_output_dir/events/InputEventInit.h",
+  "$blink_core_output_dir/events/KeyboardEventInit.cpp",
+  "$blink_core_output_dir/events/KeyboardEventInit.h",
+  "$blink_core_output_dir/events/MessageEventInit.cpp",
+  "$blink_core_output_dir/events/MessageEventInit.h",
+  "$blink_core_output_dir/events/MouseEventInit.cpp",
+  "$blink_core_output_dir/events/MouseEventInit.h",
+  "$blink_core_output_dir/events/PageTransitionEventInit.cpp",
+  "$blink_core_output_dir/events/PageTransitionEventInit.h",
+  "$blink_core_output_dir/events/PointerEventInit.cpp",
+  "$blink_core_output_dir/events/PointerEventInit.h",
+  "$blink_core_output_dir/events/PopStateEventInit.cpp",
+  "$blink_core_output_dir/events/PopStateEventInit.h",
+  "$blink_core_output_dir/events/ProgressEventInit.cpp",
+  "$blink_core_output_dir/events/ProgressEventInit.h",
+  "$blink_core_output_dir/events/PromiseRejectionEventInit.cpp",
+  "$blink_core_output_dir/events/PromiseRejectionEventInit.h",
+  "$blink_core_output_dir/events/SecurityPolicyViolationEventInit.cpp",
+  "$blink_core_output_dir/events/SecurityPolicyViolationEventInit.h",
+  "$blink_core_output_dir/events/TouchEventInit.cpp",
+  "$blink_core_output_dir/events/TouchEventInit.h",
+  "$blink_core_output_dir/events/TransitionEventInit.cpp",
+  "$blink_core_output_dir/events/TransitionEventInit.h",
+  "$blink_core_output_dir/events/UIEventInit.cpp",
+  "$blink_core_output_dir/events/UIEventInit.h",
+  "$blink_core_output_dir/events/WheelEventInit.cpp",
+  "$blink_core_output_dir/events/WheelEventInit.h",
+  "$blink_core_output_dir/fileapi/BlobPropertyBag.cpp",
+  "$blink_core_output_dir/fileapi/BlobPropertyBag.h",
+  "$blink_core_output_dir/fileapi/FilePropertyBag.cpp",
+  "$blink_core_output_dir/fileapi/FilePropertyBag.h",
+  "$blink_core_output_dir/frame/ScrollOptions.cpp",
+  "$blink_core_output_dir/frame/ScrollOptions.h",
+  "$blink_core_output_dir/frame/ScrollToOptions.cpp",
+  "$blink_core_output_dir/frame/ScrollToOptions.h",
+  "$blink_core_output_dir/geometry/DOMMatrixInit.cpp",
+  "$blink_core_output_dir/geometry/DOMMatrixInit.h",
+  "$blink_core_output_dir/geometry/DOMPointInit.cpp",
+  "$blink_core_output_dir/geometry/DOMPointInit.h",
+  "$blink_core_output_dir/geometry/DOMQuadInit.cpp",
+  "$blink_core_output_dir/geometry/DOMQuadInit.h",
+  "$blink_core_output_dir/geometry/DOMRectInit.cpp",
+  "$blink_core_output_dir/geometry/DOMRectInit.h",
+  "$blink_core_output_dir/html/AssignedNodesOptions.cpp",
+  "$blink_core_output_dir/html/AssignedNodesOptions.h",
+  "$blink_core_output_dir/html/ImageDataColorSettings.cpp",
+  "$blink_core_output_dir/html/ImageDataColorSettings.h",
+  "$blink_core_output_dir/html/canvas/CanvasContextCreationAttributes.cpp",
+  "$blink_core_output_dir/html/canvas/CanvasContextCreationAttributes.h",
+  "$blink_core_output_dir/html/track/TrackEventInit.cpp",
+  "$blink_core_output_dir/html/track/TrackEventInit.h",
+  "$blink_core_output_dir/imagebitmap/ImageBitmapOptions.cpp",
+  "$blink_core_output_dir/imagebitmap/ImageBitmapOptions.h",
+  "$blink_core_output_dir/input/InputDeviceCapabilitiesInit.cpp",
+  "$blink_core_output_dir/input/InputDeviceCapabilitiesInit.h",
+  "$blink_core_output_dir/mojo/MojoCreateDataPipeOptions.cpp",
+  "$blink_core_output_dir/mojo/MojoCreateDataPipeOptions.h",
+  "$blink_core_output_dir/mojo/MojoCreateDataPipeResult.cpp",
+  "$blink_core_output_dir/mojo/MojoCreateDataPipeResult.h",
+  "$blink_core_output_dir/mojo/MojoCreateMessagePipeResult.cpp",
+  "$blink_core_output_dir/mojo/MojoCreateMessagePipeResult.h",
+  "$blink_core_output_dir/mojo/MojoCreateSharedBufferResult.cpp",
+  "$blink_core_output_dir/mojo/MojoCreateSharedBufferResult.h",
+  "$blink_core_output_dir/mojo/MojoDiscardDataOptions.cpp",
+  "$blink_core_output_dir/mojo/MojoDiscardDataOptions.h",
+  "$blink_core_output_dir/mojo/MojoDuplicateBufferHandleOptions.cpp",
+  "$blink_core_output_dir/mojo/MojoDuplicateBufferHandleOptions.h",
+  "$blink_core_output_dir/mojo/MojoHandleSignals.cpp",
+  "$blink_core_output_dir/mojo/MojoHandleSignals.h",
+  "$blink_core_output_dir/mojo/MojoMapBufferResult.cpp",
+  "$blink_core_output_dir/mojo/MojoMapBufferResult.h",
+  "$blink_core_output_dir/mojo/MojoReadDataOptions.cpp",
+  "$blink_core_output_dir/mojo/MojoReadDataOptions.h",
+  "$blink_core_output_dir/mojo/MojoReadDataResult.cpp",
+  "$blink_core_output_dir/mojo/MojoReadDataResult.h",
+  "$blink_core_output_dir/mojo/MojoReadMessageFlags.cpp",
+  "$blink_core_output_dir/mojo/MojoReadMessageFlags.h",
+  "$blink_core_output_dir/mojo/MojoReadMessageResult.cpp",
+  "$blink_core_output_dir/mojo/MojoReadMessageResult.h",
+  "$blink_core_output_dir/mojo/MojoWriteDataOptions.cpp",
+  "$blink_core_output_dir/mojo/MojoWriteDataOptions.h",
+  "$blink_core_output_dir/mojo/MojoWriteDataResult.cpp",
+  "$blink_core_output_dir/mojo/MojoWriteDataResult.h",
+  "$blink_core_output_dir/offscreencanvas/ImageEncodeOptions.cpp",
+  "$blink_core_output_dir/offscreencanvas/ImageEncodeOptions.h",
+  "$blink_core_output_dir/page/scrolling/ScrollStateInit.cpp",
+  "$blink_core_output_dir/page/scrolling/ScrollStateInit.h",
+  "$blink_core_output_dir/timing/PerformanceObserverInit.cpp",
+  "$blink_core_output_dir/timing/PerformanceObserverInit.h",
+  "$blink_core_output_dir/workers/WorkletOptions.cpp",
+  "$blink_core_output_dir/workers/WorkletOptions.h",
+]
+
 bindings_core_generated_union_type_files = [
   "$bindings_core_v8_output_dir/AddEventListenerOptionsOrBoolean.cpp",
   "$bindings_core_v8_output_dir/AddEventListenerOptionsOrBoolean.h",
@@ -85,6 +244,15 @@
   "$bindings_core_v8_output_dir/VideoTrackOrAudioTrackOrTextTrack.h",
 ]
 
+generated_core_testing_dictionary_files = [
+  "$blink_core_output_dir/testing/InternalDictionary.cpp",
+  "$blink_core_output_dir/testing/InternalDictionary.h",
+  "$blink_core_output_dir/testing/InternalDictionaryDerived.cpp",
+  "$blink_core_output_dir/testing/InternalDictionaryDerived.h",
+  "$blink_core_output_dir/testing/InternalDictionaryDerivedDerived.cpp",
+  "$blink_core_output_dir/testing/InternalDictionaryDerivedDerived.h",
+]
+
 generated_core_testing_callback_function_files = [
   "$bindings_core_v8_output_dir/TestCallback.cpp",
   "$bindings_core_v8_output_dir/TestCallback.h",
@@ -154,32 +322,22 @@
 }
 
 idl_impl("bindings_core_impl_generated") {
-  dict_idls = core_dictionary_idl_files + core_testing_dictionary_idl_files
-  non_dict_outputs = bindings_core_generated_union_type_files +
-                     generated_core_testing_callback_function_files +
-                     generated_core_callback_function_files
-  non_dict_output_dir = bindings_core_v8_output_dir
+  sources = core_dictionary_idl_files + core_testing_dictionary_idl_files
+  outputs = bindings_core_generated_union_type_files +
+            generated_core_dictionary_files +
+            generated_core_testing_dictionary_files +
+            generated_core_testing_callback_function_files +
+            generated_core_callback_function_files
+  output_dir = bindings_core_v8_output_dir
   target_component = "core"
 }
 
-# Even though the idl_impl() call above generates .cpp and .h files for both
-# |core_dictionary_idl_files| and |core_testing_dictionary_idl_files|, we need
-# to do some manual processing because the generated files are used in
-# different targets.
-generated_core_testing_dictionary_files =
-    process_file_template(
-        core_testing_dictionary_idl_files,
-        [
-          "$blink_core_output_dir/testing/{{source_name_part}}.cpp",
-          "$blink_core_output_dir/testing/{{source_name_part}}.h",
-        ])
-
 # Compile the non-test sources generated above.
 blink_core_sources("bindings_core_impl") {
-  _non_testing_sources = get_target_outputs(":bindings_core_impl_generated") -
-                         generated_core_testing_dictionary_files -
-                         generated_core_testing_callback_function_files
-  sources = _non_testing_sources + bindings_core_generated_interface_files
+  sources = bindings_core_generated_union_type_files +
+            generated_core_dictionary_files +
+            bindings_core_generated_interface_files +
+            generated_core_callback_function_files
 
   deps = [
     ":bindings_core_v8_generated",
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptModule.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptModule.cpp
index ca0f630..127708d 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptModule.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptModule.cpp
@@ -101,7 +101,8 @@
 
 void ScriptModule::ReportException(ScriptState* script_state,
                                    v8::Local<v8::Value> exception,
-                                   const String& file_name) {
+                                   const String& file_name,
+                                   const TextPosition& start_position) {
   // We ensure module-related code is not executed without the flag.
   // https://crbug.com/715376
   CHECK(RuntimeEnabledFeatures::moduleScriptsEnabled());
@@ -111,7 +112,8 @@
   v8::TryCatch try_catch(isolate);
   try_catch.SetVerbose(true);
 
-  V8ScriptRunner::ReportExceptionForModule(isolate, exception, file_name);
+  V8ScriptRunner::ReportExceptionForModule(isolate, exception, file_name,
+                                           start_position);
 }
 
 Vector<String> ScriptModule::ModuleRequests(ScriptState* script_state) {
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptModule.h b/third_party/WebKit/Source/bindings/core/v8/ScriptModule.h
index 2dccaa57..3487124 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptModule.h
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptModule.h
@@ -46,7 +46,8 @@
   void Evaluate(ScriptState*) const;
   static void ReportException(ScriptState*,
                               v8::Local<v8::Value> exception,
-                              const String& file_name);
+                              const String& file_name,
+                              const TextPosition& start_position);
 
   Vector<String> ModuleRequests(ScriptState*);
 
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.cpp b/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.cpp
index 55e2fd88..eb3d167 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.cpp
@@ -521,17 +521,19 @@
   return v8::ScriptCompiler::CompileModule(isolate, &script_source);
 }
 
-void V8ScriptRunner::ReportExceptionForModule(v8::Isolate* isolate,
-                                              v8::Local<v8::Value> exception,
-                                              const String& file_name) {
+void V8ScriptRunner::ReportExceptionForModule(
+    v8::Isolate* isolate,
+    v8::Local<v8::Value> exception,
+    const String& file_name,
+    const TextPosition& start_position) {
   // |origin| is for compiling a fragment that throws |exception|.
   // Therefore |is_module| is false and |access_control_status| is
   // kSharableCrossOrigin.
   AccessControlStatus access_control_status = kSharableCrossOrigin;
   v8::ScriptOrigin origin(
       V8String(isolate, file_name),
-      v8::Integer::New(isolate, 0),  // line_offset
-      v8::Integer::New(isolate, 0),  // col_offset
+      v8::Integer::New(isolate, start_position.line_.ZeroBasedInt()),
+      v8::Integer::New(isolate, start_position.column_.ZeroBasedInt()),
       v8::Boolean::New(isolate, access_control_status == kSharableCrossOrigin),
       v8::Local<v8::Integer>(),    // script id
       v8::String::Empty(isolate),  // source_map_url
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.h b/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.h
index 80442abc7..ebff9136 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.h
+++ b/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.h
@@ -120,7 +120,8 @@
   // Only to be used from ScriptModule::ReportException().
   static void ReportExceptionForModule(v8::Isolate*,
                                        v8::Local<v8::Value> exception,
-                                       const String& file_name);
+                                       const String& file_name,
+                                       const TextPosition&);
 
   static uint32_t TagForParserCache(CachedMetadataHandler*);
   static uint32_t TagForCodeCache(CachedMetadataHandler*);
diff --git a/third_party/WebKit/Source/bindings/modules/v8/BUILD.gn b/third_party/WebKit/Source/bindings/modules/v8/BUILD.gn
index 10eaaa9c..961fabe 100644
--- a/third_party/WebKit/Source/bindings/modules/v8/BUILD.gn
+++ b/third_party/WebKit/Source/bindings/modules/v8/BUILD.gn
@@ -27,10 +27,11 @@
 }
 
 idl_impl("bindings_modules_impl_generated") {
-  dict_idls = modules_dictionary_idl_files
-  non_dict_outputs = bindings_modules_generated_union_type_files +
-                     generated_modules_callback_function_files
-  non_dict_output_dir = bindings_modules_v8_output_dir
+  sources = modules_dictionary_idl_files
+  outputs = bindings_modules_generated_union_type_files +
+            generated_modules_dictionary_files +
+            generated_modules_callback_function_files
+  output_dir = bindings_modules_v8_output_dir
   target_component = "modules"
 }
 
diff --git a/third_party/WebKit/Source/bindings/scripts/scripts.gni b/third_party/WebKit/Source/bindings/scripts/scripts.gni
index 9fefa29..fc7b26c 100644
--- a/third_party/WebKit/Source/bindings/scripts/scripts.gni
+++ b/third_party/WebKit/Source/bindings/scripts/scripts.gni
@@ -245,17 +245,12 @@
   }
 }
 
-# Runs idl_compiler.py to generate IDL dictionary impl files, unions and
-# callback functions.
+# Runs the idl_compiler to generate IDL dictionary and union impl files.
 #
 # Parameters:
-#   dict_idls = a list of dictionary IDL files to process. the callback and
-#               union IDL file names are already known and do not need to be
-#               specified.
-#   non_dict_outputs = a list of files generated from callback functions and
-#                      unions. the list of files generated from |dict_idls| is
-#                      added automatically and does not need to be specified.
-#   non_dict_output_dir = the directory to put the non-dict output files.
+#   sources = a list of IDL files to process
+#   outputs = a list of files to write to
+#   output_dir = the directory to put the output files
 #   target_component = component to generate code for
 template("idl_impl") {
   dictionary_impl_output_dir = "$root_gen_dir/blink/"
@@ -263,7 +258,7 @@
   action(target_name) {
     script = "//third_party/WebKit/Source/bindings/scripts/idl_compiler.py"
     idl_files_list = "$target_gen_dir/${target_name}_file_list.tmp"
-    write_file(idl_files_list, rebase_path(invoker.dict_idls, root_build_dir))
+    write_file(idl_files_list, rebase_path(invoker.sources, root_build_dir))
 
     inputs = idl_lexer_parser_files + idl_compiler_files  # to be explicit (covered by parsetab)
     inputs += [
@@ -272,27 +267,14 @@
       "$bindings_scripts_output_dir/cached_jinja_templates.stamp",
       "$bindings_dir/IDLExtendedAttributes.txt",
     ]
-    inputs += [ idl_files_list ] + invoker.dict_idls
-    outputs = invoker.non_dict_outputs
-
-    # Derive the names of the generated dictionary impl files. Contrary to
-    # generated interfaces, callbacks and unions, these files go to
-    # $root_gen_dir/blink/{core,modules}/<module name>/<IDLName>.{cpp,h}.
-    foreach(dict_idl, invoker.dict_idls) {
-      rel_path = rebase_path(dict_idl, "//third_party/WebKit/Source")
-      impl_dir = get_path_info(rel_path, "dir")
-      idl_name = get_path_info(rel_path, "name")
-      outputs += [
-        "${dictionary_impl_output_dir}$impl_dir/$idl_name.cpp",
-        "${dictionary_impl_output_dir}$impl_dir/$idl_name.h",
-      ]
-    }
+    inputs += [ idl_files_list ] + invoker.sources
+    outputs = invoker.outputs
 
     args = [
       "--cache-dir",
       rebase_path(bindings_scripts_output_dir, root_build_dir),
       "--output-dir",
-      rebase_path(invoker.non_dict_output_dir, root_build_dir),
+      rebase_path(invoker.output_dir, root_build_dir),
       "--impl-output-dir",
       rebase_path(dictionary_impl_output_dir, root_build_dir),
       "--info-dir",
diff --git a/third_party/WebKit/Source/core/BUILD.gn b/third_party/WebKit/Source/core/BUILD.gn
index 0d030dc..49adc98 100644
--- a/third_party/WebKit/Source/core/BUILD.gn
+++ b/third_party/WebKit/Source/core/BUILD.gn
@@ -1184,6 +1184,8 @@
     "css/resolver/MatchResultTest.cpp",
     "css/resolver/ScopedStyleResolverTest.cpp",
     "css/resolver/SharedStyleFinderTest.cpp",
+    "css/threaded/CSSToLengthConversionDataThreadedTest.cpp",
+    "css/threaded/FilterOperationResolverThreadedTest.cpp",
     "dom/AttrTest.cpp",
     "dom/CSSSelectorWatchTest.cpp",
     "dom/DOMImplementationTest.cpp",
diff --git a/third_party/WebKit/Source/core/css/CSSToLengthConversionData.h b/third_party/WebKit/Source/core/css/CSSToLengthConversionData.h
index b76897d..1744c6e 100644
--- a/third_party/WebKit/Source/core/css/CSSToLengthConversionData.h
+++ b/third_party/WebKit/Source/core/css/CSSToLengthConversionData.h
@@ -49,7 +49,7 @@
   DISALLOW_NEW();
 
  public:
-  class FontSizes {
+  class CORE_EXPORT FontSizes {
     DISALLOW_NEW();
 
    public:
@@ -68,7 +68,7 @@
     const Font* font_;
   };
 
-  class ViewportSize {
+  class CORE_EXPORT ViewportSize {
     DISALLOW_NEW();
 
    public:
diff --git a/third_party/WebKit/Source/core/css/parser/CSSParserContext.cpp b/third_party/WebKit/Source/core/css/parser/CSSParserContext.cpp
index 9b6974e5..5d36453 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSParserContext.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSParserContext.cpp
@@ -146,9 +146,15 @@
 }
 
 const CSSParserContext* StrictCSSParserContext() {
-  DEFINE_STATIC_LOCAL(CSSParserContext, strict_context,
-                      (CSSParserContext::Create(kHTMLStandardMode)));
-  return &strict_context;
+  DEFINE_THREAD_SAFE_STATIC_LOCAL(ThreadSpecific<Persistent<CSSParserContext>>,
+                                  strict_context_pool, ());
+  Persistent<CSSParserContext>& context = *strict_context_pool;
+  if (!context) {
+    context = CSSParserContext::Create(kHTMLStandardMode);
+    context.RegisterAsStaticReference();
+  }
+
+  return context;
 }
 
 KURL CSSParserContext::CompleteURL(const String& url) const {
diff --git a/third_party/WebKit/Source/core/css/threaded/CSSToLengthConversionDataThreadedTest.cpp b/third_party/WebKit/Source/core/css/threaded/CSSToLengthConversionDataThreadedTest.cpp
new file mode 100644
index 0000000..d3eb3b9
--- /dev/null
+++ b/third_party/WebKit/Source/core/css/threaded/CSSToLengthConversionDataThreadedTest.cpp
@@ -0,0 +1,94 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/css/CSSToLengthConversionData.h"
+
+#include "core/css/threaded/MultiThreadedTestUtil.h"
+#include "platform/Length.h"
+#include "platform/fonts/Font.h"
+#include "platform/fonts/FontDescription.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blink {
+
+TSAN_TEST(CSSToLengthConversionDataThreadedTest, Construction) {
+  RunOnThreads([]() {
+    FontDescription fontDescription;
+    Font font(fontDescription);
+    CSSToLengthConversionData::FontSizes fontSizes(16, 16, &font);
+    CSSToLengthConversionData::ViewportSize viewportSize(0, 0);
+    CSSToLengthConversionData conversionData(nullptr, fontSizes, viewportSize,
+                                             1);
+  });
+}
+
+TSAN_TEST(CSSToLengthConversionDataThreadedTest, ConversionEm) {
+  RunOnThreads([]() {
+    FontDescription fontDescription;
+    Font font(fontDescription);
+    CSSToLengthConversionData::FontSizes fontSizes(16, 16, &font);
+    CSSToLengthConversionData::ViewportSize viewportSize(0, 0);
+    CSSToLengthConversionData conversionData(nullptr, fontSizes, viewportSize,
+                                             1);
+
+    CSSPrimitiveValue& value =
+        *CSSPrimitiveValue::Create(3.14, CSSPrimitiveValue::UnitType::kEms);
+
+    Length length = value.ConvertToLength(conversionData);
+    EXPECT_EQ(length.Value(), 50.24f);
+  });
+}
+
+TSAN_TEST(CSSToLengthConversionDataThreadedTest, ConversionPixel) {
+  RunOnThreads([]() {
+    FontDescription fontDescription;
+    Font font(fontDescription);
+    CSSToLengthConversionData::FontSizes fontSizes(16, 16, &font);
+    CSSToLengthConversionData::ViewportSize viewportSize(0, 0);
+    CSSToLengthConversionData conversionData(nullptr, fontSizes, viewportSize,
+                                             1);
+
+    CSSPrimitiveValue& value =
+        *CSSPrimitiveValue::Create(44, CSSPrimitiveValue::UnitType::kPixels);
+
+    Length length = value.ConvertToLength(conversionData);
+    EXPECT_EQ(length.Value(), 44);
+  });
+}
+
+TSAN_TEST(CSSToLengthConversionDataThreadedTest, ConversionViewport) {
+  RunOnThreads([]() {
+    FontDescription fontDescription;
+    Font font(fontDescription);
+    CSSToLengthConversionData::FontSizes fontSizes(16, 16, &font);
+    CSSToLengthConversionData::ViewportSize viewportSize(0, 0);
+    CSSToLengthConversionData conversionData(nullptr, fontSizes, viewportSize,
+                                             1);
+
+    CSSPrimitiveValue& value = *CSSPrimitiveValue::Create(
+        1, CSSPrimitiveValue::UnitType::kViewportWidth);
+
+    Length length = value.ConvertToLength(conversionData);
+    EXPECT_EQ(length.Value(), 0);
+  });
+}
+
+TSAN_TEST(CSSToLengthConversionDataThreadedTest, ConversionRem) {
+  RunOnThreads([]() {
+    FontDescription fontDescription;
+    Font font(fontDescription);
+    CSSToLengthConversionData::FontSizes fontSizes(16, 16, &font);
+    CSSToLengthConversionData::ViewportSize viewportSize(0, 0);
+    CSSToLengthConversionData conversionData(nullptr, fontSizes, viewportSize,
+                                             1);
+
+    CSSPrimitiveValue& value =
+        *CSSPrimitiveValue::Create(1, CSSPrimitiveValue::UnitType::kRems);
+
+    Length length = value.ConvertToLength(conversionData);
+    EXPECT_EQ(length.Value(), 16);
+  });
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/threaded/FilterOperationResolverThreadedTest.cpp b/third_party/WebKit/Source/core/css/threaded/FilterOperationResolverThreadedTest.cpp
new file mode 100644
index 0000000..78b489b
--- /dev/null
+++ b/third_party/WebKit/Source/core/css/threaded/FilterOperationResolverThreadedTest.cpp
@@ -0,0 +1,91 @@
+// Copyright 2017 The Chromium 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/resolver/FilterOperationResolver.h"
+
+#include "core/css/parser/CSSParser.h"
+#include "core/css/parser/CSSParserContext.h"
+#include "core/css/threaded/MultiThreadedTestUtil.h"
+#include "core/style/FilterOperation.h"
+#include "platform/fonts/Font.h"
+#include "platform/fonts/FontDescription.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blink {
+
+TSAN_TEST(FilterOperationResolverThreadedTest, SimpleMatrixFilter) {
+  RunOnThreads([]() {
+    const CSSValue* value =
+        CSSParser::ParseSingleValue(CSSPropertyFilter, "sepia(50%)");
+    ASSERT_TRUE(value);
+
+    FilterOperations fo =
+        FilterOperationResolver::CreateOffscreenFilterOperations(*value);
+    ASSERT_EQ(fo.size(), 1ul);
+    EXPECT_EQ(*fo.at(0), *BasicColorMatrixFilterOperation::Create(
+                             0.5, FilterOperation::SEPIA));
+  });
+}
+
+TSAN_TEST(FilterOperationResolverThreadedTest, SimpleTransferFilter) {
+  RunOnThreads([]() {
+    const CSSValue* value =
+        CSSParser::ParseSingleValue(CSSPropertyFilter, "brightness(50%)");
+    ASSERT_TRUE(value);
+
+    FilterOperations fo =
+        FilterOperationResolver::CreateOffscreenFilterOperations(*value);
+    ASSERT_EQ(fo.size(), 1ul);
+    EXPECT_EQ(*fo.at(0), *BasicComponentTransferFilterOperation::Create(
+                             0.5, FilterOperation::BRIGHTNESS));
+  });
+}
+
+TSAN_TEST(FilterOperationResolverThreadedTest, SimpleBlurFilter) {
+  RunOnThreads([]() {
+    const CSSValue* value =
+        CSSParser::ParseSingleValue(CSSPropertyFilter, "blur(10px)");
+    ASSERT_TRUE(value);
+
+    FilterOperations fo =
+        FilterOperationResolver::CreateOffscreenFilterOperations(*value);
+    ASSERT_EQ(fo.size(), 1ul);
+    EXPECT_EQ(*fo.at(0),
+              *BlurFilterOperation::Create(Length(10, LengthType::kFixed)));
+  });
+}
+
+TSAN_TEST(FilterOperationResolverThreadedTest, SimpleDropShadow) {
+  RunOnThreads([]() {
+    const CSSValue* value = CSSParser::ParseSingleValue(
+        CSSPropertyFilter, "drop-shadow(10px 5px 1px black)");
+    ASSERT_TRUE(value);
+
+    FilterOperations fo =
+        FilterOperationResolver::CreateOffscreenFilterOperations(*value);
+    ASSERT_EQ(fo.size(), 1ul);
+    EXPECT_EQ(*fo.at(0), *DropShadowFilterOperation::Create(ShadowData(
+                             FloatPoint(10, 5), 1, 0, ShadowStyle::kNormal,
+                             StyleColor(Color::kBlack))));
+  });
+}
+
+TSAN_TEST(FilterOperationResolverThreadedTest, CompoundFilter) {
+  RunOnThreads([]() {
+    const CSSValue* value = CSSParser::ParseSingleValue(
+        CSSPropertyFilter, "sepia(50%) brightness(50%)");
+    ASSERT_TRUE(value);
+
+    FilterOperations fo =
+        FilterOperationResolver::CreateOffscreenFilterOperations(*value);
+    EXPECT_FALSE(fo.IsEmpty());
+    ASSERT_EQ(fo.size(), 2ul);
+    EXPECT_EQ(*fo.at(0), *BasicColorMatrixFilterOperation::Create(
+                             0.5, FilterOperation::SEPIA));
+    EXPECT_EQ(*fo.at(1), *BasicComponentTransferFilterOperation::Create(
+                             0.5, FilterOperation::BRIGHTNESS));
+  });
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/threaded/MultiThreadedTestUtil.h b/third_party/WebKit/Source/core/css/threaded/MultiThreadedTestUtil.h
index 97fc204b..772ee69 100644
--- a/third_party/WebKit/Source/core/css/threaded/MultiThreadedTestUtil.h
+++ b/third_party/WebKit/Source/core/css/threaded/MultiThreadedTestUtil.h
@@ -46,7 +46,6 @@
  public:
   // RunOnThreads run a closure num_threads * callbacks_per_thread times.
   // The default for this is 10*100 = 1000 times.
-
   template <typename FunctionType, typename... Ps>
   void RunOnThreads(FunctionType function, Ps&&... parameters) {
     Vector<std::unique_ptr<WebThreadSupportingGC>> threads;
diff --git a/third_party/WebKit/Source/core/dom/AXObject.h b/third_party/WebKit/Source/core/dom/AXObject.h
index ae51855..8760067 100644
--- a/third_party/WebKit/Source/core/dom/AXObject.h
+++ b/third_party/WebKit/Source/core/dom/AXObject.h
@@ -142,7 +142,6 @@
 
 enum AccessibilityState {
   kAXBusyState,
-  kAXCheckedState,
   kAXEnabledState,
   kAXExpandedState,
   kAXFocusableState,
@@ -154,7 +153,6 @@
   kAXMultilineState,
   kAXMultiselectableState,
   kAXOffscreenState,
-  kAXPressedState,
   kAXProtectedState,
   kAXReadonlyState,
   kAXRequiredState,
diff --git a/third_party/WebKit/Source/core/dom/AccessibleNode.cpp b/third_party/WebKit/Source/core/dom/AccessibleNode.cpp
index 81dd859..ce37b24 100644
--- a/third_party/WebKit/Source/core/dom/AccessibleNode.cpp
+++ b/third_party/WebKit/Source/core/dom/AccessibleNode.cpp
@@ -141,6 +141,8 @@
       return element->FastGetAttribute(aria_orientationAttr);
     case AOMStringProperty::kPlaceholder:
       return element->FastGetAttribute(aria_placeholderAttr);
+    case AOMStringProperty::kPressed:
+      return element->FastGetAttribute(aria_pressedAttr);
     case AOMStringProperty::kRelevant:
       return element->FastGetAttribute(aria_relevantAttr);
     case AOMStringProperty::kRole:
@@ -511,6 +513,15 @@
   NotifyAttributeChanged(aria_posinsetAttr);
 }
 
+AtomicString AccessibleNode::pressed() const {
+  return GetProperty(element_, AOMStringProperty::kPressed);
+}
+
+void AccessibleNode::setPressed(const AtomicString& pressed) {
+  SetStringProperty(AOMStringProperty::kPressed, pressed);
+  NotifyAttributeChanged(aria_pressedAttr);
+}
+
 bool AccessibleNode::readOnly(bool& is_null) const {
   return GetProperty(element_, AOMBooleanProperty::kReadOnly, is_null);
 }
diff --git a/third_party/WebKit/Source/core/dom/AccessibleNode.h b/third_party/WebKit/Source/core/dom/AccessibleNode.h
index f894480..709f787 100644
--- a/third_party/WebKit/Source/core/dom/AccessibleNode.h
+++ b/third_party/WebKit/Source/core/dom/AccessibleNode.h
@@ -30,6 +30,7 @@
   kLive,
   kOrientation,
   kPlaceholder,
+  kPressed,
   kRelevant,
   kRole,
   kRoleDescription,
@@ -181,6 +182,9 @@
   uint32_t posInSet(bool& is_null) const;
   void setPosInSet(uint32_t, bool is_null);
 
+  AtomicString pressed() const;
+  void setPressed(const AtomicString&);
+
   bool readOnly(bool& is_null) const;
   void setReadOnly(bool, bool is_null);
 
diff --git a/third_party/WebKit/Source/core/dom/AccessibleNode.idl b/third_party/WebKit/Source/core/dom/AccessibleNode.idl
index 4bbf09f..6be7392 100644
--- a/third_party/WebKit/Source/core/dom/AccessibleNode.idl
+++ b/third_party/WebKit/Source/core/dom/AccessibleNode.idl
@@ -30,6 +30,7 @@
     attribute DOMString? orientation;
     attribute DOMString? placeholder;
     attribute unsigned long? posInSet;
+    attribute DOMString? pressed;
     attribute boolean? readOnly;
     attribute DOMString? relevant;
     attribute boolean? required;
diff --git a/third_party/WebKit/Source/core/dom/ModulatorImpl.cpp b/third_party/WebKit/Source/core/dom/ModulatorImpl.cpp
index 0bbce98..878ea9f5 100644
--- a/third_party/WebKit/Source/core/dom/ModulatorImpl.cpp
+++ b/third_party/WebKit/Source/core/dom/ModulatorImpl.cpp
@@ -195,7 +195,7 @@
     ScriptModule::ReportException(
         script_state_.Get(),
         module_script->CreateInstantiationErrorInternal(isolate),
-        module_script->BaseURL().GetString());
+        module_script->BaseURL().GetString(), module_script->StartPosition());
     return;
   }
 
diff --git a/third_party/WebKit/Source/core/dom/ModuleScript.cpp b/third_party/WebKit/Source/core/dom/ModuleScript.cpp
index abe84a9..fd65ecc 100644
--- a/third_party/WebKit/Source/core/dom/ModuleScript.cpp
+++ b/third_party/WebKit/Source/core/dom/ModuleScript.cpp
@@ -35,7 +35,7 @@
     return nullptr;
 
   return CreateInternal(source_text, modulator, result, base_url, nonce,
-                        parser_state, credentials_mode);
+                        parser_state, credentials_mode, start_position);
 }
 
 ModuleScript* ModuleScript::CreateInternal(
@@ -45,7 +45,8 @@
     const KURL& base_url,
     const String& nonce,
     ParserDisposition parser_state,
-    WebURLRequest::FetchCredentialsMode credentials_mode) {
+    WebURLRequest::FetchCredentialsMode credentials_mode,
+    const TextPosition& start_position) {
   // https://html.spec.whatwg.org/#creating-a-module-script
   // Step 7. Set script's module record to result.
   // Step 8. Set script's base URL to the script base URL provided.
@@ -57,7 +58,7 @@
   // [not specced] |source_text| is saved for CSP checks.
   ModuleScript* module_script =
       new ModuleScript(modulator, result, base_url, nonce, parser_state,
-                       credentials_mode, source_text);
+                       credentials_mode, source_text, start_position);
 
   // Step 5, a part of ParseModule(): Passing script as the last parameter
   // here ensures result.[[HostDefined]] will be script.
@@ -75,7 +76,8 @@
     WebURLRequest::FetchCredentialsMode credentials_mode) {
   String dummy_source_text = "";
   return CreateInternal(dummy_source_text, modulator, record, base_url, nonce,
-                        parser_state, credentials_mode);
+                        parser_state, credentials_mode,
+                        TextPosition::MinimumPosition());
 }
 
 ModuleScript::ModuleScript(Modulator* settings_object,
@@ -84,7 +86,8 @@
                            const String& nonce,
                            ParserDisposition parser_state,
                            WebURLRequest::FetchCredentialsMode credentials_mode,
-                           const String& source_text)
+                           const String& source_text,
+                           const TextPosition& start_position)
     : settings_object_(settings_object),
       record_(this),
       base_url_(base_url),
@@ -92,7 +95,8 @@
       nonce_(nonce),
       parser_state_(parser_state),
       credentials_mode_(credentials_mode),
-      source_text_(source_text) {
+      source_text_(source_text),
+      start_position_(start_position) {
   if (record.IsNull()) {
     // We allow empty records for module infra tests which never touch records.
     // This should never happen outside unit tests.
diff --git a/third_party/WebKit/Source/core/dom/ModuleScript.h b/third_party/WebKit/Source/core/dom/ModuleScript.h
index 2f4bbbcd..389e1e75 100644
--- a/third_party/WebKit/Source/core/dom/ModuleScript.h
+++ b/third_party/WebKit/Source/core/dom/ModuleScript.h
@@ -77,6 +77,8 @@
   }
   const String& Nonce() const { return nonce_; }
 
+  const TextPosition& StartPosition() const { return start_position_; }
+
   DECLARE_TRACE();
   DECLARE_TRACE_WRAPPERS();
 
@@ -87,7 +89,8 @@
                const String& nonce,
                ParserDisposition parser_state,
                WebURLRequest::FetchCredentialsMode credentials_mode,
-               const String& source_text);
+               const String& source_text,
+               const TextPosition& start_position);
 
   static ModuleScript* CreateInternal(const String& source_text,
                                       Modulator*,
@@ -95,7 +98,8 @@
                                       const KURL& base_url,
                                       const String& nonce,
                                       ParserDisposition,
-                                      WebURLRequest::FetchCredentialsMode);
+                                      WebURLRequest::FetchCredentialsMode,
+                                      const TextPosition&);
 
   ScriptType GetScriptType() const override { return ScriptType::kModule; }
   bool IsEmpty() const override;
@@ -147,6 +151,8 @@
 
   // For CSP check.
   const String source_text_;
+
+  const TextPosition start_position_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/BUILD.gn b/third_party/WebKit/Source/core/editing/BUILD.gn
index 6dfdba7..f6cb0331 100644
--- a/third_party/WebKit/Source/core/editing/BUILD.gn
+++ b/third_party/WebKit/Source/core/editing/BUILD.gn
@@ -204,10 +204,16 @@
     "markers/DocumentMarkerList.h",
     "markers/DocumentMarkerListEditor.cpp",
     "markers/DocumentMarkerListEditor.h",
+    "markers/GrammarMarker.cpp",
+    "markers/GrammarMarker.h",
     "markers/GrammarMarkerListImpl.cpp",
     "markers/GrammarMarkerListImpl.h",
+    "markers/SpellCheckMarker.cpp",
+    "markers/SpellCheckMarker.h",
     "markers/SpellCheckMarkerListImpl.cpp",
     "markers/SpellCheckMarkerListImpl.h",
+    "markers/SpellingMarker.cpp",
+    "markers/SpellingMarker.h",
     "markers/SpellingMarkerListImpl.cpp",
     "markers/SpellingMarkerListImpl.h",
     "markers/TextMatchMarker.h",
@@ -319,7 +325,9 @@
     "markers/DocumentMarkerListEditorTest.cpp",
     "markers/DocumentMarkerTest.cpp",
     "markers/GrammarMarkerListImplTest.cpp",
+    "markers/GrammarMarkerTest.cpp",
     "markers/SpellingMarkerListImplTest.cpp",
+    "markers/SpellingMarkerTest.cpp",
     "markers/TextMatchMarkerListImplTest.cpp",
     "serializers/StyledMarkupSerializerTest.cpp",
     "spellcheck/IdleSpellCheckCallbackTest.cpp",
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp b/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
index 8bd538ef..5ff8ed7d 100644
--- a/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
+++ b/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
@@ -85,6 +85,24 @@
          (node.IsShadowRoot() && node.OwnerShadowHost()->GetLayoutObject());
 }
 
+template <typename Strategy>
+Node* StartNode(Node* start_container, int start_offset) {
+  if (start_container->IsCharacterDataNode())
+    return start_container;
+  if (Node* child = Strategy::ChildAt(*start_container, start_offset))
+    return child;
+  if (!start_offset)
+    return start_container;
+  return Strategy::NextSkippingChildren(*start_container);
+}
+
+template <typename Strategy>
+Node* EndNode(const Node& end_container, int end_offset) {
+  if (!end_container.IsCharacterDataNode() && end_offset > 0)
+    return Strategy::ChildAt(end_container, end_offset - 1);
+  return nullptr;
+}
+
 // This function is like Range::pastLastNode, except for the fact that it can
 // climb up out of shadow trees and ignores all nodes that will be skipped in
 // |advance()|.
@@ -144,7 +162,6 @@
 
 }  // namespace
 
-// TODO(xiaochengh): Most members should be initialized in-place, not here.
 template <typename Strategy>
 TextIteratorAlgorithm<Strategy>::TextIteratorAlgorithm(
     const EphemeralRangeTemplate<Strategy>& range,
@@ -158,20 +175,21 @@
     const PositionTemplate<Strategy>& start,
     const PositionTemplate<Strategy>& end,
     const TextIteratorBehavior& behavior)
-    : start_container_(nullptr),
-      start_offset_(0),
-      end_container_(nullptr),
-      end_offset_(0),
-      needs_another_newline_(false),
-      needs_handle_replaced_element_(false),
-      last_text_node_(nullptr),
+    : start_container_(start.ComputeContainerNode()),
+      start_offset_(start.ComputeOffsetInContainerNode()),
+      end_container_(end.ComputeContainerNode()),
+      end_offset_(end.ComputeOffsetInContainerNode()),
+      end_node_(EndNode<Strategy>(*end_container_, end_offset_)),
+      past_end_node_(PastLastNode<Strategy>(*end_container_, end_offset_)),
+      node_(StartNode<Strategy>(start_container_, start_offset_)),
+      iteration_progress_(kHandledNone),
+      shadow_depth_(
+          ShadowDepthOf<Strategy>(*start_container_, *end_container_)),
       behavior_(AdjustBehaviorFlags<Strategy>(behavior)),
-      should_stop_(false),
-      handle_shadow_root_(false),
       text_state_(behavior_),
       text_node_handler_(behavior_, &text_state_) {
-  DCHECK(start.IsNotNull());
-  DCHECK(end.IsNotNull());
+  DCHECK(start_container_);
+  DCHECK(end_container_);
 
   // TODO(dglazkov): TextIterator should not be created for documents that don't
   // have a frame, but it currently still happens in some cases. See
@@ -183,43 +201,10 @@
   // in release build.
   CHECK_LE(start, end);
 
-  Node* const start_container = start.ComputeContainerNode();
-  const int start_offset = start.ComputeOffsetInContainerNode();
-  Node* const end_container = end.ComputeContainerNode();
-  const int end_offset = end.ComputeOffsetInContainerNode();
-
-  // Remember the range - this does not change.
-  start_container_ = start_container;
-  start_offset_ = start_offset;
-  end_container_ = end_container;
-  end_offset_ = end_offset;
-  end_node_ =
-      end_container && !end_container->IsCharacterDataNode() && end_offset > 0
-          ? Strategy::ChildAt(*end_container, end_offset - 1)
-          : nullptr;
-
-  shadow_depth_ = ShadowDepthOf<Strategy>(*start_container, *end_container);
-
-  // Set up the current node for processing.
-  if (start_container->IsCharacterDataNode())
-    node_ = start_container;
-  else if (Node* child = Strategy::ChildAt(*start_container, start_offset))
-    node_ = child;
-  else if (!start_offset)
-    node_ = start_container;
-  else
-    node_ = Strategy::NextSkippingChildren(*start_container);
-
   if (!node_)
     return;
 
   fully_clipped_stack_.SetUpFullyClippedStack(node_);
-  iteration_progress_ = kHandledNone;
-
-  // Calculate first out of bounds node.
-  past_end_node_ = end_container
-                       ? PastLastNode<Strategy>(*end_container, end_offset)
-                       : nullptr;
 
   // Identify the first run.
   Advance();
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIterator.h b/third_party/WebKit/Source/core/editing/iterators/TextIterator.h
index 2b0290b..f2e00dc 100644
--- a/third_party/WebKit/Source/core/editing/iterators/TextIterator.h
+++ b/third_party/WebKit/Source/core/editing/iterators/TextIterator.h
@@ -194,6 +194,16 @@
                        int position,
                        int copy_length) const;
 
+  // The range.
+  const Member<Node> start_container_;
+  const int start_offset_;
+  const Member<Node> end_container_;
+  const int end_offset_;
+  // |m_endNode| stores |Strategy::childAt(*m_endContainer, m_endOffset - 1)|,
+  // if it exists, or |nullptr| otherwise.
+  const Member<Node> end_node_;
+  const Member<Node> past_end_node_;
+
   // Current position, not necessarily of the text being returned, but position
   // as we walk through the DOM tree.
   Member<Node> node_;
@@ -201,20 +211,10 @@
   FullyClippedStateStackAlgorithm<Strategy> fully_clipped_stack_;
   int shadow_depth_;
 
-  // The range.
-  Member<Node> start_container_;
-  int start_offset_;
-  Member<Node> end_container_;
-  int end_offset_;
-  // |m_endNode| stores |Strategy::childAt(*m_endContainer, m_endOffset - 1)|,
-  // if it exists, or |nullptr| otherwise.
-  Member<Node> end_node_;
-  Member<Node> past_end_node_;
-
   // Used when there is still some pending text from the current node; when
   // these are false, we go back to normal iterating.
-  bool needs_another_newline_;
-  bool needs_handle_replaced_element_;
+  bool needs_another_newline_ = false;
+  bool needs_handle_replaced_element_ = false;
 
   Member<Text> last_text_node_;
 
@@ -222,10 +222,10 @@
 
   // Used when stopsOnFormControls() is true to determine if the iterator should
   // keep advancing.
-  bool should_stop_;
+  bool should_stop_ = false;
   // Used for use counter |InnerTextWithShadowTree| and
   // |SelectionToStringWithShadowTree|, we should not use other purpose.
-  bool handle_shadow_root_;
+  bool handle_shadow_root_ = false;
 
   // Contains state of emitted text.
   TextIteratorTextState text_state_;
diff --git a/third_party/WebKit/Source/core/editing/markers/DocumentMarker.cpp b/third_party/WebKit/Source/core/editing/markers/DocumentMarker.cpp
index 7e9f2b1..7ecc322 100644
--- a/third_party/WebKit/Source/core/editing/markers/DocumentMarker.cpp
+++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarker.cpp
@@ -35,52 +35,15 @@
 
 namespace blink {
 
-DocumentMarkerDetails::~DocumentMarkerDetails() {}
-
-class DocumentMarkerDescription final : public DocumentMarkerDetails {
- public:
-  static DocumentMarkerDescription* Create(const String&);
-
-  const String& Description() const { return description_; }
-  bool IsDescription() const override { return true; }
-
- private:
-  explicit DocumentMarkerDescription(const String& description)
-      : description_(description) {}
-
-  String description_;
-};
-
-DocumentMarkerDescription* DocumentMarkerDescription::Create(
-    const String& description) {
-  return new DocumentMarkerDescription(description);
-}
-
-inline DocumentMarkerDescription* ToDocumentMarkerDescription(
-    DocumentMarkerDetails* details) {
-  if (details && details->IsDescription())
-    return static_cast<DocumentMarkerDescription*>(details);
-  return 0;
-}
+DocumentMarker::~DocumentMarker() = default;
 
 DocumentMarker::DocumentMarker(MarkerType type,
                                unsigned start_offset,
                                unsigned end_offset)
     : type_(type), start_offset_(start_offset), end_offset_(end_offset) {
-  DCHECK_LT(start_offset, end_offset);
+  DCHECK_LT(start_offset_, end_offset_);
 }
 
-DocumentMarker::DocumentMarker(MarkerType type,
-                               unsigned start_offset,
-                               unsigned end_offset,
-                               const String& description)
-    : type_(type),
-      start_offset_(start_offset),
-      end_offset_(end_offset),
-      details_(description.IsEmpty()
-                   ? nullptr
-                   : DocumentMarkerDescription::Create(description)) {}
-
 Optional<DocumentMarker::MarkerOffsets>
 DocumentMarker::ComputeOffsetsAfterShift(unsigned offset,
                                          unsigned old_length,
@@ -132,15 +95,4 @@
   end_offset_ += delta;
 }
 
-const String& DocumentMarker::Description() const {
-  if (DocumentMarkerDescription* details =
-          ToDocumentMarkerDescription(details_.Get()))
-    return details->Description();
-  return g_empty_string;
-}
-
-DEFINE_TRACE(DocumentMarker) {
-  visitor->Trace(details_);
-}
-
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/markers/DocumentMarker.h b/third_party/WebKit/Source/core/editing/markers/DocumentMarker.h
index 2d7169c..0ab8fa7 100644
--- a/third_party/WebKit/Source/core/editing/markers/DocumentMarker.h
+++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarker.h
@@ -32,12 +32,11 @@
 
 namespace blink {
 
-class DocumentMarkerDetails;
-
 // A range of a node within a document that is "marked", such as the range of a
 // misspelled word. It optionally includes a description that could be displayed
 // in the user interface.
-class CORE_EXPORT DocumentMarker : public GarbageCollected<DocumentMarker> {
+class CORE_EXPORT DocumentMarker
+    : public GarbageCollectedFinalized<DocumentMarker> {
  public:
   enum MarkerTypeIndex {
     kSpellingMarkerIndex = 0,
@@ -128,20 +127,12 @@
     MisspellingMarkers() : MarkerTypes(kSpelling | kGrammar) {}
   };
 
-  DocumentMarker(MarkerType,
-                 unsigned start_offset,
-                 unsigned end_offset,
-                 const String& description);
+  virtual ~DocumentMarker();
 
   MarkerType GetType() const { return type_; }
   unsigned StartOffset() const { return start_offset_; }
   unsigned EndOffset() const { return end_offset_; }
 
-  const String& Description() const;
-  DocumentMarkerDetails* Details() const;
-
-  void ClearDetails() { details_.Clear(); }
-
   struct MarkerOffsets {
     unsigned start_offset;
     unsigned end_offset;
@@ -157,7 +148,7 @@
   void SetEndOffset(unsigned offset) { end_offset_ = offset; }
   void ShiftOffsets(int delta);
 
-  DECLARE_TRACE();
+  DEFINE_INLINE_VIRTUAL_TRACE() {}
 
  protected:
   DocumentMarker(MarkerType, unsigned start_offset, unsigned end_offset);
@@ -166,27 +157,12 @@
   const MarkerType type_;
   unsigned start_offset_;
   unsigned end_offset_;
-  Member<DocumentMarkerDetails> details_;
 
   DISALLOW_COPY_AND_ASSIGN(DocumentMarker);
 };
 
 using DocumentMarkerVector = HeapVector<Member<DocumentMarker>>;
 
-inline DocumentMarkerDetails* DocumentMarker::Details() const {
-  return details_.Get();
-}
-
-class DocumentMarkerDetails
-    : public GarbageCollectedFinalized<DocumentMarkerDetails> {
- public:
-  DocumentMarkerDetails() {}
-  virtual ~DocumentMarkerDetails();
-  virtual bool IsDescription() const { return false; }
-
-  DEFINE_INLINE_VIRTUAL_TRACE() {}
-};
-
 }  // namespace blink
 
 #endif  // DocumentMarker_h
diff --git a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp
index 0064a7f..55800d22 100644
--- a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp
+++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp
@@ -37,7 +37,9 @@
 #include "core/editing/markers/CompositionMarker.h"
 #include "core/editing/markers/CompositionMarkerListImpl.h"
 #include "core/editing/markers/DocumentMarkerListEditor.h"
+#include "core/editing/markers/GrammarMarker.h"
 #include "core/editing/markers/GrammarMarkerListImpl.h"
+#include "core/editing/markers/SpellingMarker.h"
 #include "core/editing/markers/SpellingMarkerListImpl.h"
 #include "core/editing/markers/TextMatchMarker.h"
 #include "core/editing/markers/TextMatchMarkerListImpl.h"
@@ -125,24 +127,16 @@
 
 void DocumentMarkerController::AddSpellingMarker(const EphemeralRange& range,
                                                  const String& description) {
-  AddSpellCheckMarker(range, DocumentMarker::kSpelling, description);
+  AddMarkerInternal(range, [&description](int start_offset, int end_offset) {
+    return new SpellingMarker(start_offset, end_offset, description);
+  });
 }
 
 void DocumentMarkerController::AddGrammarMarker(const EphemeralRange& range,
                                                 const String& description) {
-  AddSpellCheckMarker(range, DocumentMarker::kGrammar, description);
-}
-
-void DocumentMarkerController::AddSpellCheckMarker(
-    const EphemeralRange& range,
-    DocumentMarker::MarkerType type,
-    const String& description) {
-  DCHECK(type == DocumentMarker::kSpelling || type == DocumentMarker::kGrammar)
-      << type;
-  AddMarkerInternal(
-      range, [type, &description](int start_offset, int end_offset) {
-        return new DocumentMarker(type, start_offset, end_offset, description);
-      });
+  AddMarkerInternal(range, [&description](int start_offset, int end_offset) {
+    return new GrammarMarker(start_offset, end_offset, description);
+  });
 }
 
 void DocumentMarkerController::AddTextMatchMarker(
diff --git a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.h b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.h
index 22ada19..eae9dcd 100644
--- a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.h
+++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.h
@@ -114,9 +114,6 @@
       const EphemeralRange&,
       std::function<DocumentMarker*(int, int)> create_marker_from_offsets);
   void AddMarkerToNode(Node*, DocumentMarker*);
-  void AddSpellCheckMarker(const EphemeralRange&,
-                           DocumentMarker::MarkerType,
-                           const String& description = g_empty_string);
 
   using MarkerLists = HeapVector<Member<DocumentMarkerList>,
                                  DocumentMarker::kMarkerTypeIndexesCount>;
diff --git a/third_party/WebKit/Source/core/editing/markers/GrammarMarker.cpp b/third_party/WebKit/Source/core/editing/markers/GrammarMarker.cpp
new file mode 100644
index 0000000..32cfbb6
--- /dev/null
+++ b/third_party/WebKit/Source/core/editing/markers/GrammarMarker.cpp
@@ -0,0 +1,19 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/editing/markers/GrammarMarker.h"
+
+namespace blink {
+
+GrammarMarker::GrammarMarker(unsigned start_offset,
+                             unsigned end_offset,
+                             const String& description)
+    : SpellCheckMarker(DocumentMarker::kGrammar,
+                       start_offset,
+                       end_offset,
+                       description) {
+  DCHECK_LT(start_offset, end_offset);
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/markers/GrammarMarker.h b/third_party/WebKit/Source/core/editing/markers/GrammarMarker.h
new file mode 100644
index 0000000..6bf39c5
--- /dev/null
+++ b/third_party/WebKit/Source/core/editing/markers/GrammarMarker.h
@@ -0,0 +1,28 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GrammarMarker_h
+#define GrammarMarker_h
+
+#include "core/editing/markers/SpellCheckMarker.h"
+
+namespace blink {
+
+// A subclass of DocumentMarker used to store information specific to grammar
+// markers. Spelling and grammar markers are identical except that they mark
+// either spelling or grammar errors, respectively, so nearly all functionality
+// is delegated to a common base class, SpellCheckMarker.
+class CORE_EXPORT GrammarMarker final : public SpellCheckMarker {
+ public:
+  GrammarMarker(unsigned start_offset,
+                unsigned end_offset,
+                const String& description);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(GrammarMarker);
+};
+
+}  // namespace blink
+
+#endif
diff --git a/third_party/WebKit/Source/core/editing/markers/GrammarMarkerTest.cpp b/third_party/WebKit/Source/core/editing/markers/GrammarMarkerTest.cpp
new file mode 100644
index 0000000..dd69d9d
--- /dev/null
+++ b/third_party/WebKit/Source/core/editing/markers/GrammarMarkerTest.cpp
@@ -0,0 +1,30 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/editing/markers/GrammarMarker.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blink {
+
+const char* const kDescription = "Test description";
+
+class GrammarMarkerTest : public ::testing::Test {};
+
+TEST_F(GrammarMarkerTest, MarkerType) {
+  DocumentMarker* marker = new GrammarMarker(0, 1, kDescription);
+  EXPECT_EQ(DocumentMarker::kGrammar, marker->GetType());
+}
+
+TEST_F(GrammarMarkerTest, IsSpellCheckMarker) {
+  DocumentMarker* marker = new GrammarMarker(0, 1, kDescription);
+  EXPECT_TRUE(IsSpellCheckMarker(*marker));
+}
+
+TEST_F(GrammarMarkerTest, ConstructorAndGetters) {
+  GrammarMarker* marker = new GrammarMarker(0, 1, kDescription);
+  EXPECT_EQ(kDescription, marker->Description());
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/markers/SpellCheckMarker.cpp b/third_party/WebKit/Source/core/editing/markers/SpellCheckMarker.cpp
new file mode 100644
index 0000000..04952394
--- /dev/null
+++ b/third_party/WebKit/Source/core/editing/markers/SpellCheckMarker.cpp
@@ -0,0 +1,23 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/editing/markers/SpellCheckMarker.h"
+
+namespace blink {
+
+SpellCheckMarker::SpellCheckMarker(DocumentMarker::MarkerType type,
+                                   unsigned start_offset,
+                                   unsigned end_offset,
+                                   const String& description)
+    : DocumentMarker(type, start_offset, end_offset),
+      description_(description) {
+  DCHECK_LT(start_offset, end_offset);
+}
+
+bool IsSpellCheckMarker(const DocumentMarker& marker) {
+  DocumentMarker::MarkerType type = marker.GetType();
+  return type == DocumentMarker::kSpelling || type == DocumentMarker::kGrammar;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/markers/SpellCheckMarker.h b/third_party/WebKit/Source/core/editing/markers/SpellCheckMarker.h
new file mode 100644
index 0000000..053f7c5
--- /dev/null
+++ b/third_party/WebKit/Source/core/editing/markers/SpellCheckMarker.h
@@ -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.
+
+#ifndef SpellCheckMarker_h
+#define SpellCheckMarker_h
+
+#include "core/editing/markers/DocumentMarker.h"
+
+namespace blink {
+
+// A subclass of DocumentMarker used to implement functionality shared between
+// spelling and grammar markers. These two marker types both store a
+// description string that can contain suggested replacements for a misspelling
+// or grammar error.
+class CORE_EXPORT SpellCheckMarker : public DocumentMarker {
+ public:
+  SpellCheckMarker(DocumentMarker::MarkerType,
+                   unsigned start_offset,
+                   unsigned end_offset,
+                   const String& description);
+
+  const String& Description() const { return description_; }
+
+ private:
+  const String description_;
+
+  DISALLOW_COPY_AND_ASSIGN(SpellCheckMarker);
+};
+
+bool CORE_EXPORT IsSpellCheckMarker(const DocumentMarker&);
+
+DEFINE_TYPE_CASTS(SpellCheckMarker,
+                  DocumentMarker,
+                  marker,
+                  IsSpellCheckMarker(*marker),
+                  IsSpellCheckMarker(marker));
+
+}  // namespace blink
+
+#endif
diff --git a/third_party/WebKit/Source/core/editing/markers/SpellingMarker.cpp b/third_party/WebKit/Source/core/editing/markers/SpellingMarker.cpp
new file mode 100644
index 0000000..fa0b1b1b
--- /dev/null
+++ b/third_party/WebKit/Source/core/editing/markers/SpellingMarker.cpp
@@ -0,0 +1,19 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/editing/markers/SpellingMarker.h"
+
+namespace blink {
+
+SpellingMarker::SpellingMarker(unsigned start_offset,
+                               unsigned end_offset,
+                               const String& description)
+    : SpellCheckMarker(DocumentMarker::kSpelling,
+                       start_offset,
+                       end_offset,
+                       description) {
+  DCHECK_LT(start_offset, end_offset);
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/markers/SpellingMarker.h b/third_party/WebKit/Source/core/editing/markers/SpellingMarker.h
new file mode 100644
index 0000000..d4dac785
--- /dev/null
+++ b/third_party/WebKit/Source/core/editing/markers/SpellingMarker.h
@@ -0,0 +1,28 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SpellingMarker_h
+#define SpellingMarker_h
+
+#include "core/editing/markers/SpellCheckMarker.h"
+
+namespace blink {
+
+// A subclass of DocumentMarker used to store information specific to spelling
+// markers. Spelling and grammar markers are identical except that they mark
+// either spelling or grammar errors, respectively, so nearly all functionality
+// is delegated to a common base class, SpellCheckMarker.
+class CORE_EXPORT SpellingMarker final : public SpellCheckMarker {
+ public:
+  SpellingMarker(unsigned start_offset,
+                 unsigned end_offset,
+                 const String& description);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SpellingMarker);
+};
+
+}  // namespace blink
+
+#endif
diff --git a/third_party/WebKit/Source/core/editing/markers/SpellingMarkerListImplTest.cpp b/third_party/WebKit/Source/core/editing/markers/SpellingMarkerListImplTest.cpp
index 39b353f..a73974d 100644
--- a/third_party/WebKit/Source/core/editing/markers/SpellingMarkerListImplTest.cpp
+++ b/third_party/WebKit/Source/core/editing/markers/SpellingMarkerListImplTest.cpp
@@ -4,6 +4,7 @@
 
 #include "core/editing/markers/SpellCheckMarkerListImpl.h"
 
+#include "core/editing/markers/SpellingMarker.h"
 #include "core/editing/markers/SpellingMarkerListImpl.h"
 #include "platform/heap/Handle.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -18,8 +19,7 @@
   SpellingMarkerListImplTest() : marker_list_(new SpellingMarkerListImpl()) {}
 
   DocumentMarker* CreateMarker(unsigned start_offset, unsigned end_offset) {
-    return new DocumentMarker(DocumentMarker::kSpelling, start_offset,
-                              end_offset, g_empty_string);
+    return new SpellingMarker(start_offset, end_offset, g_empty_string);
   }
 
   Persistent<SpellingMarkerListImpl> marker_list_;
diff --git a/third_party/WebKit/Source/core/editing/markers/SpellingMarkerTest.cpp b/third_party/WebKit/Source/core/editing/markers/SpellingMarkerTest.cpp
new file mode 100644
index 0000000..bffeadfd
--- /dev/null
+++ b/third_party/WebKit/Source/core/editing/markers/SpellingMarkerTest.cpp
@@ -0,0 +1,30 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/editing/markers/SpellingMarker.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blink {
+
+const char* const kDescription = "Test description";
+
+class SpellingMarkerTest : public ::testing::Test {};
+
+TEST_F(SpellingMarkerTest, MarkerType) {
+  DocumentMarker* marker = new SpellingMarker(0, 1, kDescription);
+  EXPECT_EQ(DocumentMarker::kSpelling, marker->GetType());
+}
+
+TEST_F(SpellingMarkerTest, IsSpellCheckMarker) {
+  DocumentMarker* marker = new SpellingMarker(0, 1, kDescription);
+  EXPECT_TRUE(IsSpellCheckMarker(*marker));
+}
+
+TEST_F(SpellingMarkerTest, ConstructorAndGetters) {
+  SpellingMarker* marker = new SpellingMarker(0, 1, kDescription);
+  EXPECT_EQ(kDescription, marker->Description());
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/exported/WebViewBase.h b/third_party/WebKit/Source/core/exported/WebViewBase.h
index be06f39..a80e23f9 100644
--- a/third_party/WebKit/Source/core/exported/WebViewBase.h
+++ b/third_party/WebKit/Source/core/exported/WebViewBase.h
@@ -125,6 +125,10 @@
 
   virtual WebSettingsImpl* SettingsImpl() = 0;
 
+  virtual void RequestDecode(
+      sk_sp<SkImage>,
+      std::unique_ptr<WTF::Function<void(bool)>> callback) = 0;
+
   using WebWidget::GetPagePopup;
   virtual PagePopup* OpenPagePopup(PagePopupClient*) = 0;
   virtual void ClosePagePopup(PagePopup*) = 0;
diff --git a/third_party/WebKit/Source/core/frame/LocalFrameView.cpp b/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
index 0eacc963..5da0362 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
+++ b/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
@@ -2168,8 +2168,14 @@
       ScrollbarTheme::GetTheme().UsesOverlayScrollbars() &&
       !ShouldUseCustomScrollbars(custom_scrollbar_element);
 
-  if (!uses_overlay_scrollbars && NeedsLayout())
-    UpdateLayout();
+  if (!uses_overlay_scrollbars) {
+    if (NeedsLayout())
+      UpdateLayout();
+
+    if (frame_->IsMainFrame() &&
+        RuntimeEnabledFeatures::visualViewportAPIEnabled())
+      frame_->GetDocument()->EnqueueVisualViewportResizeEvent();
+  }
 
   if (!GetLayoutViewItem().IsNull() && GetLayoutViewItem().UsesCompositing()) {
     GetLayoutViewItem().Compositor()->FrameViewScrollbarsExistenceDidChange();
diff --git a/third_party/WebKit/Source/core/frame/WebFrameWidgetBase.cpp b/third_party/WebKit/Source/core/frame/WebFrameWidgetBase.cpp
index ee49720..9199de6 100644
--- a/third_party/WebKit/Source/core/frame/WebFrameWidgetBase.cpp
+++ b/third_party/WebKit/Source/core/frame/WebFrameWidgetBase.cpp
@@ -253,6 +253,12 @@
   GetPage()->GetPointerLockController().DidLosePointerLock();
 }
 
+void WebFrameWidgetBase::RequestDecode(
+    sk_sp<SkImage> image,
+    std::unique_ptr<WTF::Function<void(bool)>> callback) {
+  View()->RequestDecode(std::move(image), std::move(callback));
+}
+
 // TODO(665924): Remove direct dispatches of mouse events from
 // PointerLockController, instead passing them through EventHandler.
 void WebFrameWidgetBase::PointerLockMouseEvent(
diff --git a/third_party/WebKit/Source/core/frame/WebFrameWidgetBase.h b/third_party/WebKit/Source/core/frame/WebFrameWidgetBase.h
index 2abfa650..1607f22 100644
--- a/third_party/WebKit/Source/core/frame/WebFrameWidgetBase.h
+++ b/third_party/WebKit/Source/core/frame/WebFrameWidgetBase.h
@@ -86,6 +86,10 @@
   void DidLosePointerLock() override;
   void ShowContextMenu(WebMenuSourceType) override;
 
+  // Image decode functionality.
+  void RequestDecode(sk_sp<SkImage>,
+                     std::unique_ptr<WTF::Function<void(bool)>> callback);
+
  protected:
   enum DragAction { kDragEnter, kDragOver };
 
diff --git a/third_party/WebKit/Source/core/html/HTMLImageElement.cpp b/third_party/WebKit/Source/core/html/HTMLImageElement.cpp
index 6ad4929..c317ebb4 100644
--- a/third_party/WebKit/Source/core/html/HTMLImageElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLImageElement.cpp
@@ -31,6 +31,7 @@
 #include "core/css/MediaValuesDynamic.h"
 #include "core/css/parser/SizesAttributeParser.h"
 #include "core/dom/Attribute.h"
+#include "core/dom/DOMException.h"
 #include "core/dom/NodeTraversal.h"
 #include "core/dom/shadow/ShadowRoot.h"
 #include "core/frame/Deprecation.h"
@@ -51,6 +52,7 @@
 #include "core/layout/LayoutImage.h"
 #include "core/layout/api/LayoutImageItem.h"
 #include "core/loader/resource/ImageResourceContent.h"
+#include "core/page/ChromeClient.h"
 #include "core/page/Page.h"
 #include "core/style/ContentData.h"
 #include "core/svg/graphics/SVGImageForContainer.h"
@@ -92,6 +94,7 @@
       image_device_pixel_ratio_(1.0f),
       source_(nullptr),
       layout_disposition_(LayoutDisposition::kPrimaryContent),
+      decode_sequence_id_(0),
       form_was_set_by_parser_(false),
       element_created_by_parser_(created_by_parser),
       is_fallback_image_(false),
@@ -115,6 +118,7 @@
   visitor->Trace(listener_);
   visitor->Trace(form_);
   visitor->Trace(source_);
+  visitor->Trace(decode_promise_resolvers_);
   HTMLElement::Trace(visitor);
 }
 
@@ -125,6 +129,45 @@
   SelectSourceURL(ImageLoader::kUpdateSizeChanged);
 }
 
+void HTMLImageElement::RequestDecode() {
+  DCHECK(!decode_promise_resolvers_.IsEmpty());
+  LocalFrame* frame = GetDocument().GetFrame();
+  // If we don't have the image, or the document doesn't have a frame, then
+  // reject the decode, since we can't plumb the request to the correct place.
+  if (!GetImageLoader().GetImage() ||
+      !GetImageLoader().GetImage()->GetImage() || !frame) {
+    DecodeRequestFinished(decode_sequence_id_, false);
+    return;
+  }
+  Image* image = GetImageLoader().GetImage()->GetImage();
+  frame->GetChromeClient().RequestDecode(
+      frame, image->ImageForCurrentFrame(),
+      WTF::Bind(&HTMLImageElement::DecodeRequestFinished,
+                WrapWeakPersistent(this), decode_sequence_id_));
+}
+
+void HTMLImageElement::DecodeRequestFinished(uint32_t sequence_id,
+                                             bool success) {
+  // If the sequence id attached with this callback doesn't match our current
+  // sequence id, then the source of the image has changed. In other words, the
+  // decode resolved/rejected by this callback was already rejected. Since we
+  // could have had a new decode request, we have to make sure not to
+  // resolve/reject those using the stale callback.
+  if (sequence_id != decode_sequence_id_)
+    return;
+
+  if (success) {
+    for (auto& resolver : decode_promise_resolvers_)
+      resolver->Resolve();
+  } else {
+    for (auto& resolver : decode_promise_resolvers_) {
+      resolver->Reject(DOMException::Create(
+          kEncodingError, "The source image cannot be decoded"));
+    }
+  }
+  decode_promise_resolvers_.clear();
+}
+
 HTMLImageElement* HTMLImageElement::CreateForJSConstructor(Document& document) {
   HTMLImageElement* image = new HTMLImageElement(document);
   image->element_created_by_parser_ = false;
@@ -260,6 +303,14 @@
     }
   } else if (name == srcAttr || name == srcsetAttr || name == sizesAttr) {
     SelectSourceURL(ImageLoader::kUpdateIgnorePreviousError);
+    // Ensure to fail any pending decodes on possible source changes.
+    if (!decode_promise_resolvers_.IsEmpty() &&
+        params.old_value != params.new_value) {
+      DecodeRequestFinished(decode_sequence_id_, false);
+      // Increment the sequence id so that any in flight decode completion tasks
+      // will not trigger promise resolution for new decode requests.
+      ++decode_sequence_id_;
+    }
   } else if (name == usemapAttr) {
     SetIsLink(!params.new_value.IsNull());
   } else if (name == referrerpolicyAttr) {
@@ -597,6 +648,22 @@
   return abs_pos.Y();
 }
 
+ScriptPromise HTMLImageElement::decode(ScriptState* script_state,
+                                       ExceptionState& exception_state) {
+  if (!script_state->ContextIsValid()) {
+    exception_state.ThrowDOMException(kEncodingError,
+                                      "The source image cannot be decoded");
+    return ScriptPromise();
+  }
+  exception_state.ClearException();
+  decode_promise_resolvers_.push_back(
+      ScriptPromiseResolver::Create(script_state));
+  ScriptPromise promise = decode_promise_resolvers_.back()->Promise();
+  if (complete())
+    RequestDecode();
+  return promise;
+}
+
 bool HTMLImageElement::complete() const {
   return GetImageLoader().ImageComplete();
 }
@@ -613,8 +680,8 @@
 
   const AtomicString& usemap = FastGetAttribute(usemapAttr);
 
-  // If the usemap attribute starts with '#', it refers to a map element in the
-  // document.
+  // If the usemap attribute starts with '#', it refers to a map element in
+  // the document.
   if (usemap[0] == '#')
     return false;
 
@@ -812,6 +879,15 @@
   }
 }
 
+void HTMLImageElement::ImageNotifyFinished(bool success) {
+  if (decode_promise_resolvers_.IsEmpty())
+    return;
+  if (success)
+    RequestDecode();
+  else
+    DecodeRequestFinished(decode_sequence_id_, false);
+}
+
 void HTMLImageElement::AssociateWith(HTMLFormElement* form) {
   if (form && form->isConnected()) {
     form_ = form;
diff --git a/third_party/WebKit/Source/core/html/HTMLImageElement.h b/third_party/WebKit/Source/core/html/HTMLImageElement.h
index 6caecfa..c8e0200 100644
--- a/third_party/WebKit/Source/core/html/HTMLImageElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLImageElement.h
@@ -31,6 +31,7 @@
 #include "core/html/canvas/ImageElementBase.h"
 #include "platform/bindings/ActiveScriptWrappable.h"
 #include "platform/graphics/GraphicsTypes.h"
+#include "platform/heap/HeapAllocator.h"
 #include "platform/loader/fetch/FetchParameters.h"
 #include "platform/loader/fetch/ResourceResponse.h"
 
@@ -99,6 +100,8 @@
   int x() const;
   int y() const;
 
+  ScriptPromise decode(ScriptState*, ExceptionState&);
+
   bool complete() const;
 
   bool HasPendingActivity() const final {
@@ -133,6 +136,8 @@
   FormAssociated* ToFormAssociatedOrNull() override { return this; };
   void AssociateWith(HTMLFormElement*) override;
 
+  void ImageNotifyFinished(bool success);
+
  protected:
   // Controls how an image element appears in the layout. See:
   // https://html.spec.whatwg.org/multipage/embedded-content.html#image-request
@@ -185,6 +190,13 @@
   bool IsInteractiveContent() const override;
   Image* ImageContents() override;
 
+  // Issues a request to decode the image to the chrome client.
+  void RequestDecode();
+  // A callback that is called when the image with the given sequence id has
+  // been decoded (either successfully or not). This is a signal to
+  // resolve/reject the promises that have been handed out.
+  void DecodeRequestFinished(uint32_t sequence_id, bool success);
+
   void ResetFormOwner();
   ImageCandidate FindBestFitImageFromPictureParent();
   void SetBestFitURLAndDPRFromImageCandidate(const ImageCandidate&);
@@ -199,6 +211,8 @@
   float image_device_pixel_ratio_;
   Member<HTMLSourceElement> source_;
   LayoutDisposition layout_disposition_;
+  HeapVector<Member<ScriptPromiseResolver>> decode_promise_resolvers_;
+  uint32_t decode_sequence_id_;
   unsigned form_was_set_by_parser_ : 1;
   unsigned element_created_by_parser_ : 1;
   unsigned is_fallback_image_ : 1;
diff --git a/third_party/WebKit/Source/core/html/HTMLImageElement.idl b/third_party/WebKit/Source/core/html/HTMLImageElement.idl
index 44abb3f..732668c 100644
--- a/third_party/WebKit/Source/core/html/HTMLImageElement.idl
+++ b/third_party/WebKit/Source/core/html/HTMLImageElement.idl
@@ -55,4 +55,6 @@
     // https://dev.w3.org/csswg/cssom-view/#extensions-to-the-htmlimageelement-interface
     [MeasureAs=HTMLImageElementX] readonly attribute long x;
     [MeasureAs=HTMLImageElementY] readonly attribute long y;
+
+    [RuntimeEnabled=JSImageDecode, CallWith=ScriptState, RaisesException] Promise decode();
 };
diff --git a/third_party/WebKit/Source/core/html/HTMLImageLoader.cpp b/third_party/WebKit/Source/core/html/HTMLImageLoader.cpp
index c25df5b..54827a9 100644
--- a/third_party/WebKit/Source/core/html/HTMLImageLoader.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLImageLoader.cpp
@@ -75,6 +75,7 @@
 
   bool load_error = cached_image->ErrorOccurred();
   if (isHTMLImageElement(*element)) {
+    toHTMLImageElement(element)->ImageNotifyFinished(!load_error);
     if (load_error)
       toHTMLImageElement(element)->EnsureCollapsedOrFallbackContent();
     else
diff --git a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
index 328a072..95ba140 100644
--- a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
+++ b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
@@ -846,6 +846,12 @@
   return loader;
 }
 
+void FrameFetchContext::Detach() {
+  // This is needed to break a reference cycle in which off-heap
+  // ComputedStyle is involved. See https://crbug.com/383860 for details.
+  document_ = nullptr;
+}
+
 DEFINE_TRACE(FrameFetchContext) {
   visitor->Trace(document_loader_);
   visitor->Trace(document_);
diff --git a/third_party/WebKit/Source/core/loader/FrameFetchContext.h b/third_party/WebKit/Source/core/loader/FrameFetchContext.h
index d93ad791..493770d 100644
--- a/third_party/WebKit/Source/core/loader/FrameFetchContext.h
+++ b/third_party/WebKit/Source/core/loader/FrameFetchContext.h
@@ -155,6 +155,8 @@
   std::unique_ptr<WebURLLoader> CreateURLLoader(
       const ResourceRequest&) override;
 
+  void Detach() override;
+
   DECLARE_VIRTUAL_TRACE();
 
  private:
@@ -197,10 +199,7 @@
   void AddConsoleMessage(ConsoleMessage*) const override;
 
   Member<DocumentLoader> document_loader_;
-  // FIXME: Oilpan: Ideally this should just be a traced Member but that will
-  // currently leak because ComputedStyle and its data are not on the heap.
-  // See crbug.com/383860 for details.
-  WeakMember<Document> document_;
+  Member<Document> document_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/page/ChromeClient.h b/third_party/WebKit/Source/core/page/ChromeClient.h
index de24ec3..21a903d 100644
--- a/third_party/WebKit/Source/core/page/ChromeClient.h
+++ b/third_party/WebKit/Source/core/page/ChromeClient.h
@@ -372,6 +372,13 @@
     return nullptr;
   }
 
+  virtual void RequestDecode(
+      LocalFrame*,
+      sk_sp<SkImage> image,
+      std::unique_ptr<WTF::Function<void(bool)>> callback) {
+    (*callback)(false);
+  }
+
   DECLARE_TRACE();
 
  protected:
diff --git a/third_party/WebKit/Source/core/testing/Internals.cpp b/third_party/WebKit/Source/core/testing/Internals.cpp
index cdc6f2a..6829be1f 100644
--- a/third_party/WebKit/Source/core/testing/Internals.cpp
+++ b/third_party/WebKit/Source/core/testing/Internals.cpp
@@ -65,6 +65,7 @@
 #include "core/editing/iterators/TextIterator.h"
 #include "core/editing/markers/DocumentMarker.h"
 #include "core/editing/markers/DocumentMarkerController.h"
+#include "core/editing/markers/SpellCheckMarker.h"
 #include "core/editing/markers/TextMatchMarker.h"
 #include "core/editing/serializers/Serialization.h"
 #include "core/editing/spellcheck/IdleSpellCheckCallback.h"
@@ -1010,9 +1011,9 @@
                                            unsigned index,
                                            ExceptionState& exception_state) {
   DocumentMarker* marker = MarkerAt(node, marker_type, index, exception_state);
-  if (!marker)
+  if (!marker || !IsSpellCheckMarker(*marker))
     return String();
-  return marker->Description();
+  return ToSpellCheckMarker(marker)->Description();
 }
 
 static WTF::Optional<TextMatchMarker::MatchStatus> MatchStatusFrom(
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/ApplicationCacheItemsView.js b/third_party/WebKit/Source/devtools/front_end/resources/ApplicationCacheItemsView.js
index aeccfea5..0a275d39 100644
--- a/third_party/WebKit/Source/devtools/front_end/resources/ApplicationCacheItemsView.js
+++ b/third_party/WebKit/Source/devtools/front_end/resources/ApplicationCacheItemsView.js
@@ -136,14 +136,9 @@
     }
   }
 
-  _update() {
-    this._model.requestApplicationCache(this._frameId, this._updateCallback.bind(this));
-  }
+  async _update() {
+    var applicationCache = await this._model.requestApplicationCache(this._frameId);
 
-  /**
-   * @param {?Protocol.ApplicationCache.ApplicationCache} applicationCache
-   */
-  _updateCallback(applicationCache) {
     if (!applicationCache || !applicationCache.manifestURL) {
       delete this._manifest;
       delete this._creationTime;
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/ApplicationCacheModel.js b/third_party/WebKit/Source/devtools/front_end/resources/ApplicationCacheModel.js
index 9114b726..024f0174 100644
--- a/third_party/WebKit/Source/devtools/front_end/resources/ApplicationCacheModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/resources/ApplicationCacheModel.js
@@ -51,14 +51,20 @@
     this._onLine = true;
   }
 
-  _frameNavigated(event) {
+  /**
+   * @param {!Common.Event} event
+   */
+  async _frameNavigated(event) {
     var frame = /** @type {!SDK.ResourceTreeFrame} */ (event.data);
     if (frame.isMainFrame()) {
       this._mainFrameNavigated();
       return;
     }
 
-    this._agent.getManifestForFrame(frame.id, this._manifestForFrameLoaded.bind(this, frame.id));
+    var frameId = frame.id;
+    var manifestURL = await this._agent.getManifestForFrame(frameId);
+    if (manifestURL !== null && !manifestURL)
+      this._frameManifestRemoved(frameId);
   }
 
   /**
@@ -75,39 +81,10 @@
     this.dispatchEventToListeners(Resources.ApplicationCacheModel.Events.FrameManifestsReset);
   }
 
-  _mainFrameNavigated() {
-    this._agent.getFramesWithManifests(this._framesWithManifestsLoaded.bind(this));
-  }
-
-  /**
-   * @param {string} frameId
-   * @param {?Protocol.Error} error
-   * @param {string} manifestURL
-   */
-  _manifestForFrameLoaded(frameId, error, manifestURL) {
-    if (error) {
-      console.error(error);
-      return;
-    }
-
-    if (!manifestURL)
-      this._frameManifestRemoved(frameId);
-  }
-
-  /**
-   * @param {?Protocol.Error} error
-   * @param {!Array.<!Protocol.ApplicationCache.FrameWithManifest>} framesWithManifests
-   */
-  _framesWithManifestsLoaded(error, framesWithManifests) {
-    if (error) {
-      console.error(error);
-      return;
-    }
-
-    for (var i = 0; i < framesWithManifests.length; ++i) {
-      this._frameManifestUpdated(
-          framesWithManifests[i].frameId, framesWithManifests[i].manifestURL, framesWithManifests[i].status);
-    }
+  async _mainFrameNavigated() {
+    var framesWithManifests = await this._agent.getFramesWithManifests();
+    for (var frame of framesWithManifests || [])
+      this._frameManifestUpdated(frame.frameId, frame.manifestURL, frame.status);
   }
 
   /**
@@ -186,24 +163,10 @@
 
   /**
    * @param {string} frameId
-   * @param {function(?Protocol.ApplicationCache.ApplicationCache)} callback
+   * @return {!Promise<?Protocol.ApplicationCache.ApplicationCache>}
    */
-  requestApplicationCache(frameId, callback) {
-    /**
-     * @param {?Protocol.Error} error
-     * @param {!Protocol.ApplicationCache.ApplicationCache} applicationCache
-     */
-    function callbackWrapper(error, applicationCache) {
-      if (error) {
-        console.error(error);
-        callback(null);
-        return;
-      }
-
-      callback(applicationCache);
-    }
-
-    this._agent.getApplicationCacheForFrame(frameId, callbackWrapper);
+  requestApplicationCache(frameId) {
+    return this._agent.getApplicationCacheForFrame(frameId);
   }
 
   /**
diff --git a/third_party/WebKit/Source/devtools/scripts/build/generate_protocol_externs.py b/third_party/WebKit/Source/devtools/scripts/build/generate_protocol_externs.py
index d5817d3..2b28b1c 100755
--- a/third_party/WebKit/Source/devtools/scripts/build/generate_protocol_externs.py
+++ b/third_party/WebKit/Source/devtools/scripts/build/generate_protocol_externs.py
@@ -47,7 +47,6 @@
 ref_types = {}
 
 NON_PROMISIFIED_DOMAINS = frozenset([
-    "ApplicationCache",
     "CacheStorage",
     "CSS",
     "DOMDebugger",
diff --git a/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp b/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp
index eafe58e..8ad521c 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp
+++ b/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp
@@ -1217,26 +1217,6 @@
   return false;
 }
 
-bool AXNodeObject::IsPressed() const {
-  if (!IsButton())
-    return false;
-
-  Node* node = this->GetNode();
-  if (!node)
-    return false;
-
-  // ARIA button with aria-pressed not undefined, then check for aria-pressed
-  // attribute rather than getNode()->active()
-  if (AriaRoleAttribute() == kToggleButtonRole) {
-    if (EqualIgnoringASCIICase(GetAttribute(aria_pressedAttr), "true") ||
-        EqualIgnoringASCIICase(GetAttribute(aria_pressedAttr), "mixed"))
-      return true;
-    return false;
-  }
-
-  return node->IsActive();
-}
-
 bool AXNodeObject::IsReadOnly() const {
   Node* node = this->GetNode();
   if (!node)
diff --git a/third_party/WebKit/Source/modules/accessibility/AXNodeObject.h b/third_party/WebKit/Source/modules/accessibility/AXNodeObject.h
index f618fcc..0b779ef 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXNodeObject.h
+++ b/third_party/WebKit/Source/modules/accessibility/AXNodeObject.h
@@ -131,7 +131,6 @@
   bool IsEnabled() const override;
   AccessibilityExpanded IsExpanded() const override;
   bool IsModal() const final;
-  bool IsPressed() const final;
   bool IsReadOnly() const override;
   bool IsRequired() const final;
 
diff --git a/third_party/WebKit/Source/modules/accessibility/AXObjectCacheImpl.cpp b/third_party/WebKit/Source/modules/accessibility/AXObjectCacheImpl.cpp
index 24b31ae..53e8f65b 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXObjectCacheImpl.cpp
+++ b/third_party/WebKit/Source/modules/accessibility/AXObjectCacheImpl.cpp
@@ -993,7 +993,7 @@
   else if (attr_name == aria_labelAttr || attr_name == aria_labeledbyAttr ||
            attr_name == aria_labelledbyAttr)
     TextChanged(element);
-  else if (attr_name == aria_checkedAttr)
+  else if (attr_name == aria_checkedAttr || attr_name == aria_pressedAttr)
     CheckedStateChanged(element);
   else if (attr_name == aria_selectedAttr)
     HandleAriaSelectedChanged(element);
diff --git a/third_party/WebKit/Source/modules/accessibility/AXObjectImpl.cpp b/third_party/WebKit/Source/modules/accessibility/AXObjectImpl.cpp
index 17bc431..e7b38a2 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXObjectImpl.cpp
+++ b/third_party/WebKit/Source/modules/accessibility/AXObjectImpl.cpp
@@ -449,7 +449,12 @@
     case kMenuItemRadioRole:
     case kRadioButtonRole:
     case kSwitchRole:
+    case kToggleButtonRole:
       return true;
+    case kTreeItemRole:
+    case kListBoxOptionRole:
+    case kMenuListOptionRole:
+      return AriaCheckedIsPresent();
     default:
       return false;
   }
@@ -459,40 +464,45 @@
 // Because an AXMenuListOption (<option>) can
 // have an ARIA role of menuitemcheckbox/menuitemradio
 // yet does not inherit from AXNodeObject
-AccessibilityButtonState AXObjectImpl::CheckedState() const {
+AccessibilityCheckedState AXObjectImpl::CheckedState() const {
   if (!IsCheckable())
-    return kButtonStateOff;
+    return kCheckedStateUndefined;
 
-  const AtomicString& checkedAttribute =
-      GetAOMPropertyOrARIAAttribute(AOMStringProperty::kChecked);
-  if (checkedAttribute) {
-    if (EqualIgnoringASCIICase(checkedAttribute, "true"))
-      return kButtonStateOn;
+  // Try ARIA checked/pressed state
+  const AccessibilityRole role = RoleValue();
+  const auto prop = role == kToggleButtonRole ? AOMStringProperty::kPressed
+                                              : AOMStringProperty::kChecked;
+  const AtomicString& checked_attribute = GetAOMPropertyOrARIAAttribute(prop);
+  if (checked_attribute) {
+    if (EqualIgnoringASCIICase(checked_attribute, "true"))
+      return kCheckedStateTrue;
 
-    if (EqualIgnoringASCIICase(checkedAttribute, "mixed")) {
-      // Only checkboxes and radios should support the mixed state.
-      const AccessibilityRole role = RoleValue();
-      if (role == kCheckBoxRole || role == kMenuItemCheckBoxRole ||
-          role == kRadioButtonRole || role == kMenuItemRadioRole)
-        return kButtonStateMixed;
+    if (EqualIgnoringASCIICase(checked_attribute, "mixed")) {
+      // Only checkable role that doesn't support mixed is the switch.
+      if (role != kSwitchRole)
+        return kCheckedStateMixed;
     }
 
-    return kButtonStateOff;
+    if (EqualIgnoringASCIICase(checked_attribute, "false"))
+      return kCheckedStateFalse;
   }
 
-  const Node* node = this->GetNode();
-  if (!node)
-    return kButtonStateOff;
+  // Native checked state
+  if (role != kToggleButtonRole) {
+    const Node* node = this->GetNode();
+    if (!node)
+      return kCheckedStateUndefined;
 
-  if (IsNativeInputInMixedState(node))
-    return kButtonStateMixed;
+    if (IsNativeInputInMixedState(node))
+      return kCheckedStateMixed;
 
-  if (isHTMLInputElement(*node) &&
-      toHTMLInputElement(*node).ShouldAppearChecked()) {
-    return kButtonStateOn;
+    if (isHTMLInputElement(*node) &&
+        toHTMLInputElement(*node).ShouldAppearChecked()) {
+      return kCheckedStateTrue;
+    }
   }
 
-  return kButtonStateOff;
+  return kCheckedStateFalse;
 }
 
 bool AXObjectImpl::IsNativeInputInMixedState(const Node* node) {
@@ -1114,17 +1124,19 @@
       return AXDefaultActionVerb::kPress;
     case kTextFieldRole:
       return AXDefaultActionVerb::kActivate;
+    case kMenuItemRadioRole:
     case kRadioButtonRole:
       return AXDefaultActionVerb::kSelect;
-    case kCheckBoxRole:
-    case kSwitchRole:
-      return CheckedState() == kButtonStateOff ? AXDefaultActionVerb::kCheck
-                                               : AXDefaultActionVerb::kUncheck;
     case kLinkRole:
       return AXDefaultActionVerb::kJump;
     case kPopUpButtonRole:
       return AXDefaultActionVerb::kOpen;
     default:
+      if (IsCheckable()) {
+        return CheckedState() != kCheckedStateTrue
+                   ? AXDefaultActionVerb::kCheck
+                   : AXDefaultActionVerb::kUncheck;
+      }
       return AXDefaultActionVerb::kClick;
   }
 }
@@ -1150,6 +1162,10 @@
   return !GetAttribute(aria_pressedAttr).IsEmpty();
 }
 
+bool AXObjectImpl::AriaCheckedIsPresent() const {
+  return !GetAttribute(aria_checkedAttr).IsEmpty();
+}
+
 bool AXObjectImpl::SupportsActiveDescendant() const {
   // According to the ARIA Spec, all ARIA composite widgets, ARIA text boxes
   // and ARIA groups should be able to expose an active descendant.
diff --git a/third_party/WebKit/Source/modules/accessibility/AXObjectImpl.h b/third_party/WebKit/Source/modules/accessibility/AXObjectImpl.h
index 9eb5526..a2a9acc8 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXObjectImpl.h
+++ b/third_party/WebKit/Source/modules/accessibility/AXObjectImpl.h
@@ -97,10 +97,11 @@
   kDefaultBehavior,
 };
 
-enum AccessibilityButtonState {
-  kButtonStateOff = 0,
-  kButtonStateOn,
-  kButtonStateMixed,
+enum AccessibilityCheckedState {
+  kCheckedStateUndefined = 0,
+  kCheckedStateFalse,
+  kCheckedStateTrue,
+  kCheckedStateMixed
 };
 
 enum AccessibilityOptionalBool {
@@ -379,7 +380,6 @@
   virtual bool IsAXTable() const { return false; }
   virtual bool IsAnchor() const { return false; }
   bool IsButton() const;
-  bool IsCheckable() const;
   bool IsCanvas() const { return RoleValue() == kCanvasRole; }
   bool IsCheckbox() const { return RoleValue() == kCheckBoxRole; }
   bool IsCheckboxOrRadio() const { return IsCheckbox() || IsRadioButton(); }
@@ -452,7 +452,6 @@
   virtual bool IsModal() const { return false; }
   virtual bool IsMultiSelectable() const { return false; }
   virtual bool IsOffScreen() const { return false; }
-  virtual bool IsPressed() const { return false; }
   virtual bool IsReadOnly() const { return false; }
   virtual bool IsRequired() const { return false; }
   virtual bool IsSelected() const { return false; }
@@ -613,7 +612,7 @@
 
   // Properties of interactive elements.
   AXDefaultActionVerb Action() const;
-  AccessibilityButtonState CheckedState() const;
+  AccessibilityCheckedState CheckedState() const;
   virtual AriaCurrentState GetAriaCurrentState() const {
     return kAriaCurrentStateUndefined;
   }
@@ -638,6 +637,7 @@
   virtual bool IsEditable() const { return false; }
   bool IsMultiline() const;
   virtual bool IsRichlyEditable() const { return false; }
+  bool AriaCheckedIsPresent() const;
   bool AriaPressedIsPresent() const;
   virtual AccessibilityRole AriaRoleAttribute() const { return kUnknownRole; }
   virtual bool AriaRoleHasPresentationalChildren() const { return false; }
@@ -884,7 +884,10 @@
   void UpdateCachedAttributeValuesIfNeeded() const;
 
  private:
+  bool IsCheckable() const;
   static bool IsNativeInputInMixedState(const Node*);
+  static bool IncludesARIAWidgetRole(const String&);
+  static bool HasInteractiveARIAAttribute(const Element&);
 
   static unsigned number_of_live_ax_objects_;
 };
diff --git a/third_party/WebKit/Source/modules/accessibility/InspectorAccessibilityAgent.cpp b/third_party/WebKit/Source/modules/accessibility/InspectorAccessibilityAgent.cpp
index 090379f..7c40c69 100644
--- a/third_party/WebKit/Source/modules/accessibility/InspectorAccessibilityAgent.cpp
+++ b/third_party/WebKit/Source/modules/accessibility/InspectorAccessibilityAgent.cpp
@@ -149,13 +149,6 @@
   return role == kColumnHeaderRole || role == kRowHeaderRole;
 }
 
-bool RoleAllowsChecked(AccessibilityRole role) {
-  return role == kMenuItemCheckBoxRole || role == kMenuItemRadioRole ||
-         role == kRadioButtonRole || role == kCheckBoxRole ||
-         role == kTreeItemRole || role == kListBoxOptionRole ||
-         role == kSwitchRole;
-}
-
 bool RoleAllowsSelected(AccessibilityRole role) {
   return role == kCellRole || role == kListBoxOptionRole || role == kRowRole ||
          role == kTabRole || role == kColumnHeaderRole ||
@@ -252,25 +245,27 @@
 void FillWidgetStates(AXObjectImpl& ax_object,
                       protocol::Array<AXProperty>& properties) {
   AccessibilityRole role = ax_object.RoleValue();
-  if (RoleAllowsChecked(role)) {
-    AccessibilityButtonState checked = ax_object.CheckedState();
-    switch (checked) {
-      case kButtonStateOff:
-        properties.addItem(
-            CreateProperty(AXWidgetStatesEnum::Checked,
-                           CreateValue("false", AXValueTypeEnum::Tristate)));
-        break;
-      case kButtonStateOn:
-        properties.addItem(
-            CreateProperty(AXWidgetStatesEnum::Checked,
-                           CreateValue("true", AXValueTypeEnum::Tristate)));
-        break;
-      case kButtonStateMixed:
-        properties.addItem(
-            CreateProperty(AXWidgetStatesEnum::Checked,
-                           CreateValue("mixed", AXValueTypeEnum::Tristate)));
-        break;
-    }
+  const char* checked_prop_val = 0;
+  switch (ax_object.CheckedState()) {
+    case kCheckedStateTrue:
+      checked_prop_val = "true";
+      break;
+    case kCheckedStateMixed:
+      checked_prop_val = "mixed";
+      break;
+    case kCheckedStateFalse:
+      checked_prop_val = "false";
+      break;
+    case kCheckedStateUndefined:
+      break;
+  }
+  if (checked_prop_val) {
+    const auto checked_prop_name = role == kToggleButtonRole
+                                       ? AXWidgetStatesEnum::Pressed
+                                       : AXWidgetStatesEnum::Checked;
+    properties.addItem(CreateProperty(
+        checked_prop_name,
+        CreateValue(checked_prop_val, AXValueTypeEnum::Tristate)));
   }
 
   AccessibilityExpanded expanded = ax_object.IsExpanded();
@@ -289,25 +284,6 @@
       break;
   }
 
-  if (role == kToggleButtonRole) {
-    if (!ax_object.IsPressed()) {
-      properties.addItem(
-          CreateProperty(AXWidgetStatesEnum::Pressed,
-                         CreateValue("false", AXValueTypeEnum::Tristate)));
-    } else {
-      const AtomicString& pressed_attr =
-          ax_object.GetAttribute(HTMLNames::aria_pressedAttr);
-      if (EqualIgnoringASCIICase(pressed_attr, "mixed"))
-        properties.addItem(
-            CreateProperty(AXWidgetStatesEnum::Pressed,
-                           CreateValue("mixed", AXValueTypeEnum::Tristate)));
-      else
-        properties.addItem(
-            CreateProperty(AXWidgetStatesEnum::Pressed,
-                           CreateValue("true", AXValueTypeEnum::Tristate)));
-    }
-  }
-
   if (RoleAllowsSelected(role)) {
     properties.addItem(
         CreateProperty(AXWidgetStatesEnum::Selected,
diff --git a/third_party/WebKit/Source/modules/modules_idl_files.gni b/third_party/WebKit/Source/modules/modules_idl_files.gni
index 86a8aa4..0c3d259 100644
--- a/third_party/WebKit/Source/modules/modules_idl_files.gni
+++ b/third_party/WebKit/Source/modules/modules_idl_files.gni
@@ -699,3 +699,349 @@
 # collision
 modules_all_dependency_idl_files =
     modules_static_dependency_idl_files + modules_generated_dependency_idl_files
+
+# Source files generated from IDL.
+generated_modules_dictionary_files = [
+  # TODO ideally this would not be listed explicitly. Rather, we would have
+  # different categories of .idl files that produce certain patterns of
+  # source files. Then these sources files can be programatically expanded
+  # from the .idl file list(s).
+  "$blink_modules_output_dir/app_banner/BeforeInstallPromptEventInit.cpp",
+  "$blink_modules_output_dir/app_banner/BeforeInstallPromptEventInit.h",
+  "$blink_modules_output_dir/background_fetch/BackgroundFetchClickEventInit.cpp",
+  "$blink_modules_output_dir/background_fetch/BackgroundFetchClickEventInit.h",
+  "$blink_modules_output_dir/background_fetch/BackgroundFetchEventInit.cpp",
+  "$blink_modules_output_dir/background_fetch/BackgroundFetchEventInit.h",
+  "$blink_modules_output_dir/background_fetch/BackgroundFetchFailEventInit.cpp",
+  "$blink_modules_output_dir/background_fetch/BackgroundFetchFailEventInit.h",
+  "$blink_modules_output_dir/background_fetch/BackgroundFetchOptions.cpp",
+  "$blink_modules_output_dir/background_fetch/BackgroundFetchOptions.h",
+  "$blink_modules_output_dir/background_fetch/BackgroundFetchedEventInit.cpp",
+  "$blink_modules_output_dir/background_fetch/BackgroundFetchedEventInit.h",
+  "$blink_modules_output_dir/background_fetch/IconDefinition.cpp",
+  "$blink_modules_output_dir/background_fetch/IconDefinition.h",
+  "$blink_modules_output_dir/background_sync/SyncEventInit.cpp",
+  "$blink_modules_output_dir/background_sync/SyncEventInit.h",
+  "$blink_modules_output_dir/bluetooth/BluetoothLEScanFilterInit.cpp",
+  "$blink_modules_output_dir/bluetooth/BluetoothLEScanFilterInit.h",
+  "$blink_modules_output_dir/bluetooth/RequestDeviceOptions.cpp",
+  "$blink_modules_output_dir/bluetooth/RequestDeviceOptions.h",
+  "$blink_modules_output_dir/cachestorage/CacheQueryOptions.cpp",
+  "$blink_modules_output_dir/cachestorage/CacheQueryOptions.h",
+  "$blink_modules_output_dir/canvas2d/CanvasRenderingContext2DSettings.cpp",
+  "$blink_modules_output_dir/canvas2d/CanvasRenderingContext2DSettings.h",
+  "$blink_modules_output_dir/canvas2d/HitRegionOptions.cpp",
+  "$blink_modules_output_dir/canvas2d/HitRegionOptions.h",
+  "$blink_modules_output_dir/credentialmanager/CredentialData.cpp",
+  "$blink_modules_output_dir/credentialmanager/CredentialData.h",
+  "$blink_modules_output_dir/credentialmanager/CredentialCreationOptions.cpp",
+  "$blink_modules_output_dir/credentialmanager/CredentialCreationOptions.h",
+  "$blink_modules_output_dir/credentialmanager/CredentialRequestOptions.cpp",
+  "$blink_modules_output_dir/credentialmanager/CredentialRequestOptions.h",
+  "$blink_modules_output_dir/credentialmanager/FederatedCredentialInit.cpp",
+  "$blink_modules_output_dir/credentialmanager/FederatedCredentialInit.h",
+  "$blink_modules_output_dir/credentialmanager/FederatedCredentialRequestOptions.cpp",
+  "$blink_modules_output_dir/credentialmanager/FederatedCredentialRequestOptions.h",
+  "$blink_modules_output_dir/credentialmanager/FormDataOptions.cpp",
+  "$blink_modules_output_dir/credentialmanager/FormDataOptions.h",
+  "$blink_modules_output_dir/credentialmanager/PasswordCredentialData.cpp",
+  "$blink_modules_output_dir/credentialmanager/PasswordCredentialData.h",
+  "$blink_modules_output_dir/device_orientation/DeviceAccelerationInit.cpp",
+  "$blink_modules_output_dir/device_orientation/DeviceAccelerationInit.h",
+  "$blink_modules_output_dir/device_orientation/DeviceMotionEventInit.cpp",
+  "$blink_modules_output_dir/device_orientation/DeviceMotionEventInit.h",
+  "$blink_modules_output_dir/device_orientation/DeviceOrientationEventInit.cpp",
+  "$blink_modules_output_dir/device_orientation/DeviceOrientationEventInit.h",
+  "$blink_modules_output_dir/device_orientation/DeviceRotationRateInit.cpp",
+  "$blink_modules_output_dir/device_orientation/DeviceRotationRateInit.h",
+  "$blink_modules_output_dir/encoding/TextDecodeOptions.cpp",
+  "$blink_modules_output_dir/encoding/TextDecodeOptions.h",
+  "$blink_modules_output_dir/encoding/TextDecoderOptions.cpp",
+  "$blink_modules_output_dir/encoding/TextDecoderOptions.h",
+  "$blink_modules_output_dir/encryptedmedia/MediaEncryptedEventInit.cpp",
+  "$blink_modules_output_dir/encryptedmedia/MediaEncryptedEventInit.h",
+  "$blink_modules_output_dir/encryptedmedia/MediaKeyMessageEventInit.cpp",
+  "$blink_modules_output_dir/encryptedmedia/MediaKeyMessageEventInit.h",
+  "$blink_modules_output_dir/encryptedmedia/MediaKeySystemConfiguration.cpp",
+  "$blink_modules_output_dir/encryptedmedia/MediaKeySystemConfiguration.h",
+  "$blink_modules_output_dir/encryptedmedia/MediaKeySystemMediaCapability.cpp",
+  "$blink_modules_output_dir/encryptedmedia/MediaKeySystemMediaCapability.h",
+  "$blink_modules_output_dir/eventsource/EventSourceInit.cpp",
+  "$blink_modules_output_dir/eventsource/EventSourceInit.h",
+  "$blink_modules_output_dir/fetch/ResponseInit.cpp",
+  "$blink_modules_output_dir/fetch/ResponseInit.h",
+  "$blink_modules_output_dir/filesystem/FileSystemFlags.cpp",
+  "$blink_modules_output_dir/filesystem/FileSystemFlags.h",
+  "$blink_modules_output_dir/gamepad/GamepadEventInit.cpp",
+  "$blink_modules_output_dir/gamepad/GamepadEventInit.h",
+  "$blink_modules_output_dir/geolocation/PositionOptions.cpp",
+  "$blink_modules_output_dir/geolocation/PositionOptions.h",
+  "$blink_modules_output_dir/imagecapture/ConstrainPoint2DParameters.cpp",
+  "$blink_modules_output_dir/imagecapture/ConstrainPoint2DParameters.h",
+  "$blink_modules_output_dir/imagecapture/PhotoSettings.cpp",
+  "$blink_modules_output_dir/imagecapture/PhotoSettings.h",
+  "$blink_modules_output_dir/imagecapture/Point2D.cpp",
+  "$blink_modules_output_dir/imagecapture/Point2D.h",
+  "$blink_modules_output_dir/indexeddb/IDBIndexParameters.cpp",
+  "$blink_modules_output_dir/indexeddb/IDBIndexParameters.h",
+  "$blink_modules_output_dir/indexeddb/IDBObjectStoreParameters.cpp",
+  "$blink_modules_output_dir/indexeddb/IDBObjectStoreParameters.h",
+  "$blink_modules_output_dir/indexeddb/IDBObserverInit.cpp",
+  "$blink_modules_output_dir/indexeddb/IDBObserverInit.h",
+  "$blink_modules_output_dir/indexeddb/IDBVersionChangeEventInit.cpp",
+  "$blink_modules_output_dir/indexeddb/IDBVersionChangeEventInit.h",
+  "$blink_modules_output_dir/media_capabilities/AudioConfiguration.cpp",
+  "$blink_modules_output_dir/media_capabilities/AudioConfiguration.h",
+  "$blink_modules_output_dir/media_capabilities/MediaConfiguration.cpp",
+  "$blink_modules_output_dir/media_capabilities/MediaConfiguration.h",
+  "$blink_modules_output_dir/media_capabilities/MediaDecodingConfiguration.cpp",
+  "$blink_modules_output_dir/media_capabilities/MediaDecodingConfiguration.h",
+  "$blink_modules_output_dir/media_capabilities/MediaEncodingConfiguration.cpp",
+  "$blink_modules_output_dir/media_capabilities/MediaEncodingConfiguration.h",
+  "$blink_modules_output_dir/media_capabilities/VideoConfiguration.cpp",
+  "$blink_modules_output_dir/media_capabilities/VideoConfiguration.h",
+  "$blink_modules_output_dir/mediarecorder/BlobEventInit.cpp",
+  "$blink_modules_output_dir/mediarecorder/BlobEventInit.h",
+  "$blink_modules_output_dir/mediarecorder/MediaRecorderOptions.cpp",
+  "$blink_modules_output_dir/mediarecorder/MediaRecorderOptions.h",
+  "$blink_modules_output_dir/mediasession/MediaImage.cpp",
+  "$blink_modules_output_dir/mediasession/MediaImage.h",
+  "$blink_modules_output_dir/mediasession/MediaMetadataInit.cpp",
+  "$blink_modules_output_dir/mediasession/MediaMetadataInit.h",
+  "$blink_modules_output_dir/mediastream/ConstrainBooleanParameters.cpp",
+  "$blink_modules_output_dir/mediastream/ConstrainBooleanParameters.h",
+  "$blink_modules_output_dir/mediastream/ConstrainDOMStringParameters.cpp",
+  "$blink_modules_output_dir/mediastream/ConstrainDOMStringParameters.h",
+  "$blink_modules_output_dir/mediastream/ConstrainDoubleRange.cpp",
+  "$blink_modules_output_dir/mediastream/ConstrainDoubleRange.h",
+  "$blink_modules_output_dir/mediastream/ConstrainLongRange.cpp",
+  "$blink_modules_output_dir/mediastream/ConstrainLongRange.h",
+  "$blink_modules_output_dir/mediastream/DoubleRange.cpp",
+  "$blink_modules_output_dir/mediastream/DoubleRange.h",
+  "$blink_modules_output_dir/mediastream/LongRange.cpp",
+  "$blink_modules_output_dir/mediastream/LongRange.h",
+  "$blink_modules_output_dir/mediastream/MediaStreamConstraints.cpp",
+  "$blink_modules_output_dir/mediastream/MediaStreamConstraints.h",
+  "$blink_modules_output_dir/mediastream/MediaStreamEventInit.cpp",
+  "$blink_modules_output_dir/mediastream/MediaStreamEventInit.h",
+  "$blink_modules_output_dir/mediastream/MediaStreamTrackEventInit.cpp",
+  "$blink_modules_output_dir/mediastream/MediaStreamTrackEventInit.h",
+  "$blink_modules_output_dir/mediastream/MediaTrackCapabilities.cpp",
+  "$blink_modules_output_dir/mediastream/MediaTrackCapabilities.h",
+  "$blink_modules_output_dir/mediastream/MediaTrackConstraintSet.cpp",
+  "$blink_modules_output_dir/mediastream/MediaTrackConstraintSet.h",
+  "$blink_modules_output_dir/mediastream/MediaTrackConstraints.cpp",
+  "$blink_modules_output_dir/mediastream/MediaTrackConstraints.h",
+  "$blink_modules_output_dir/mediastream/MediaTrackSettings.cpp",
+  "$blink_modules_output_dir/mediastream/MediaTrackSettings.h",
+  "$blink_modules_output_dir/mediastream/MediaTrackSupportedConstraints.cpp",
+  "$blink_modules_output_dir/mediastream/MediaTrackSupportedConstraints.h",
+  "$blink_modules_output_dir/nfc/NFCMessage.cpp",
+  "$blink_modules_output_dir/nfc/NFCMessage.h",
+  "$blink_modules_output_dir/nfc/NFCPushOptions.cpp",
+  "$blink_modules_output_dir/nfc/NFCPushOptions.h",
+  "$blink_modules_output_dir/nfc/NFCRecord.cpp",
+  "$blink_modules_output_dir/nfc/NFCRecord.h",
+  "$blink_modules_output_dir/nfc/NFCWatchOptions.cpp",
+  "$blink_modules_output_dir/nfc/NFCWatchOptions.h",
+  "$blink_modules_output_dir/notifications/GetNotificationOptions.cpp",
+  "$blink_modules_output_dir/notifications/GetNotificationOptions.h",
+  "$blink_modules_output_dir/notifications/NotificationAction.cpp",
+  "$blink_modules_output_dir/notifications/NotificationAction.h",
+  "$blink_modules_output_dir/notifications/NotificationEventInit.cpp",
+  "$blink_modules_output_dir/notifications/NotificationEventInit.h",
+  "$blink_modules_output_dir/notifications/NotificationOptions.cpp",
+  "$blink_modules_output_dir/notifications/NotificationOptions.h",
+  "$blink_modules_output_dir/payments/AndroidPayMethodData.cpp",
+  "$blink_modules_output_dir/payments/AndroidPayMethodData.h",
+  "$blink_modules_output_dir/payments/AndroidPayTokenization.cpp",
+  "$blink_modules_output_dir/payments/AndroidPayTokenization.h",
+  "$blink_modules_output_dir/payments/BasicCardRequest.cpp",
+  "$blink_modules_output_dir/payments/BasicCardRequest.h",
+  "$blink_modules_output_dir/payments/PaymentAppResponse.cpp",
+  "$blink_modules_output_dir/payments/PaymentAppResponse.h",
+  "$blink_modules_output_dir/payments/PaymentAppRequest.cpp",
+  "$blink_modules_output_dir/payments/PaymentAppRequest.h",
+  "$blink_modules_output_dir/payments/PaymentCurrencyAmount.cpp",
+  "$blink_modules_output_dir/payments/PaymentCurrencyAmount.h",
+  "$blink_modules_output_dir/payments/PaymentDetailsBase.cpp",
+  "$blink_modules_output_dir/payments/PaymentDetailsBase.h",
+  "$blink_modules_output_dir/payments/PaymentDetailsInit.cpp",
+  "$blink_modules_output_dir/payments/PaymentDetailsInit.h",
+  "$blink_modules_output_dir/payments/PaymentDetailsModifier.cpp",
+  "$blink_modules_output_dir/payments/PaymentDetailsModifier.h",
+  "$blink_modules_output_dir/payments/PaymentDetailsUpdate.cpp",
+  "$blink_modules_output_dir/payments/PaymentDetailsUpdate.h",
+  "$blink_modules_output_dir/payments/PaymentItem.cpp",
+  "$blink_modules_output_dir/payments/PaymentItem.h",
+  "$blink_modules_output_dir/payments/PaymentMethodData.cpp",
+  "$blink_modules_output_dir/payments/PaymentMethodData.h",
+  "$blink_modules_output_dir/payments/PaymentOptions.cpp",
+  "$blink_modules_output_dir/payments/PaymentOptions.h",
+  "$blink_modules_output_dir/payments/PaymentInstrument.cpp",
+  "$blink_modules_output_dir/payments/PaymentInstrument.h",
+  "$blink_modules_output_dir/payments/PaymentRequestUpdateEventInit.cpp",
+  "$blink_modules_output_dir/payments/PaymentRequestUpdateEventInit.h",
+  "$blink_modules_output_dir/payments/PaymentShippingOption.cpp",
+  "$blink_modules_output_dir/payments/PaymentShippingOption.h",
+  "$blink_modules_output_dir/peerconnection/RTCAnswerOptions.cpp",
+  "$blink_modules_output_dir/peerconnection/RTCAnswerOptions.h",
+  "$blink_modules_output_dir/peerconnection/RTCConfiguration.cpp",
+  "$blink_modules_output_dir/peerconnection/RTCConfiguration.h",
+  "$blink_modules_output_dir/peerconnection/RTCDataChannelEventInit.cpp",
+  "$blink_modules_output_dir/peerconnection/RTCDataChannelEventInit.h",
+  "$blink_modules_output_dir/peerconnection/RTCDTMFToneChangeEventInit.cpp",
+  "$blink_modules_output_dir/peerconnection/RTCDTMFToneChangeEventInit.h",
+  "$blink_modules_output_dir/peerconnection/RTCDataChannelInit.cpp",
+  "$blink_modules_output_dir/peerconnection/RTCDataChannelInit.h",
+  "$blink_modules_output_dir/peerconnection/RTCIceCandidateInit.cpp",
+  "$blink_modules_output_dir/peerconnection/RTCIceCandidateInit.h",
+  "$blink_modules_output_dir/peerconnection/RTCIceServer.cpp",
+  "$blink_modules_output_dir/peerconnection/RTCIceServer.h",
+  "$blink_modules_output_dir/peerconnection/RTCOfferAnswerOptions.cpp",
+  "$blink_modules_output_dir/peerconnection/RTCOfferAnswerOptions.h",
+  "$blink_modules_output_dir/peerconnection/RTCOfferOptions.cpp",
+  "$blink_modules_output_dir/peerconnection/RTCOfferOptions.h",
+  "$blink_modules_output_dir/peerconnection/RTCPeerConnectionIceEventInit.cpp",
+  "$blink_modules_output_dir/peerconnection/RTCPeerConnectionIceEventInit.h",
+  "$blink_modules_output_dir/peerconnection/RTCSessionDescriptionInit.cpp",
+  "$blink_modules_output_dir/peerconnection/RTCSessionDescriptionInit.h",
+  "$blink_modules_output_dir/permissions/MidiPermissionDescriptor.cpp",
+  "$blink_modules_output_dir/permissions/MidiPermissionDescriptor.h",
+  "$blink_modules_output_dir/permissions/PermissionDescriptor.cpp",
+  "$blink_modules_output_dir/permissions/PermissionDescriptor.h",
+  "$blink_modules_output_dir/permissions/PushPermissionDescriptor.cpp",
+  "$blink_modules_output_dir/permissions/PushPermissionDescriptor.h",
+  "$blink_modules_output_dir/presentation/PresentationConnectionAvailableEventInit.cpp",
+  "$blink_modules_output_dir/presentation/PresentationConnectionAvailableEventInit.h",
+  "$blink_modules_output_dir/presentation/PresentationConnectionCloseEventInit.cpp",
+  "$blink_modules_output_dir/presentation/PresentationConnectionCloseEventInit.h",
+  "$blink_modules_output_dir/push_messaging/PushEventInit.cpp",
+  "$blink_modules_output_dir/push_messaging/PushEventInit.h",
+  "$blink_modules_output_dir/push_messaging/PushSubscriptionOptionsInit.cpp",
+  "$blink_modules_output_dir/push_messaging/PushSubscriptionOptionsInit.h",
+  "$blink_modules_output_dir/quota/StorageEstimate.cpp",
+  "$blink_modules_output_dir/quota/StorageEstimate.h",
+  "$blink_modules_output_dir/sensor/SensorErrorEventInit.cpp",
+  "$blink_modules_output_dir/sensor/SensorErrorEventInit.h",
+  "$blink_modules_output_dir/sensor/SensorOptions.cpp",
+  "$blink_modules_output_dir/sensor/SensorOptions.h",
+  "$blink_modules_output_dir/serviceworkers/ClientQueryOptions.cpp",
+  "$blink_modules_output_dir/serviceworkers/ClientQueryOptions.h",
+  "$blink_modules_output_dir/serviceworkers/ExtendableEventInit.cpp",
+  "$blink_modules_output_dir/serviceworkers/ExtendableEventInit.h",
+  "$blink_modules_output_dir/serviceworkers/ExtendableMessageEventInit.cpp",
+  "$blink_modules_output_dir/serviceworkers/ExtendableMessageEventInit.h",
+  "$blink_modules_output_dir/serviceworkers/FetchEventInit.cpp",
+  "$blink_modules_output_dir/serviceworkers/FetchEventInit.h",
+  "$blink_modules_output_dir/serviceworkers/ForeignFetchEventInit.cpp",
+  "$blink_modules_output_dir/serviceworkers/ForeignFetchEventInit.h",
+  "$blink_modules_output_dir/serviceworkers/ForeignFetchOptions.cpp",
+  "$blink_modules_output_dir/serviceworkers/ForeignFetchOptions.h",
+  "$blink_modules_output_dir/serviceworkers/ForeignFetchResponse.cpp",
+  "$blink_modules_output_dir/serviceworkers/ForeignFetchResponse.h",
+  "$blink_modules_output_dir/serviceworkers/NavigationPreloadState.cpp",
+  "$blink_modules_output_dir/serviceworkers/NavigationPreloadState.h",
+  "$blink_modules_output_dir/serviceworkers/RegistrationOptions.cpp",
+  "$blink_modules_output_dir/serviceworkers/RegistrationOptions.h",
+  "$blink_modules_output_dir/shapedetection/FaceDetectorOptions.cpp",
+  "$blink_modules_output_dir/shapedetection/FaceDetectorOptions.h",
+  "$blink_modules_output_dir/shapedetection/Landmark.cpp",
+  "$blink_modules_output_dir/shapedetection/Landmark.h",
+  "$blink_modules_output_dir/speech/SpeechRecognitionErrorInit.cpp",
+  "$blink_modules_output_dir/speech/SpeechRecognitionErrorInit.h",
+  "$blink_modules_output_dir/speech/SpeechRecognitionEventInit.cpp",
+  "$blink_modules_output_dir/speech/SpeechRecognitionEventInit.h",
+  "$blink_modules_output_dir/storage/StorageEventInit.cpp",
+  "$blink_modules_output_dir/storage/StorageEventInit.h",
+  "$blink_modules_output_dir/vr/VRDisplayEventInit.cpp",
+  "$blink_modules_output_dir/vr/VRDisplayEventInit.h",
+  "$blink_modules_output_dir/vr/VRLayer.cpp",
+  "$blink_modules_output_dir/vr/VRLayer.h",
+  "$blink_modules_output_dir/webaudio/AnalyserOptions.cpp",
+  "$blink_modules_output_dir/webaudio/AnalyserOptions.h",
+  "$blink_modules_output_dir/webaudio/AudioBufferOptions.cpp",
+  "$blink_modules_output_dir/webaudio/AudioBufferOptions.h",
+  "$blink_modules_output_dir/webaudio/AudioBufferSourceOptions.cpp",
+  "$blink_modules_output_dir/webaudio/AudioBufferSourceOptions.h",
+  "$blink_modules_output_dir/webaudio/AudioContextOptions.cpp",
+  "$blink_modules_output_dir/webaudio/AudioContextOptions.h",
+  "$blink_modules_output_dir/webaudio/AudioNodeOptions.cpp",
+  "$blink_modules_output_dir/webaudio/AudioNodeOptions.h",
+  "$blink_modules_output_dir/webaudio/AudioProcessingEventInit.cpp",
+  "$blink_modules_output_dir/webaudio/AudioProcessingEventInit.h",
+  "$blink_modules_output_dir/webaudio/AudioTimestamp.cpp",
+  "$blink_modules_output_dir/webaudio/AudioTimestamp.h",
+  "$blink_modules_output_dir/webaudio/BiquadFilterOptions.cpp",
+  "$blink_modules_output_dir/webaudio/BiquadFilterOptions.h",
+  "$blink_modules_output_dir/webaudio/ChannelMergerOptions.cpp",
+  "$blink_modules_output_dir/webaudio/ChannelMergerOptions.h",
+  "$blink_modules_output_dir/webaudio/ChannelSplitterOptions.cpp",
+  "$blink_modules_output_dir/webaudio/ChannelSplitterOptions.h",
+  "$blink_modules_output_dir/webaudio/ConstantSourceOptions.cpp",
+  "$blink_modules_output_dir/webaudio/ConstantSourceOptions.h",
+  "$blink_modules_output_dir/webaudio/ConvolverOptions.cpp",
+  "$blink_modules_output_dir/webaudio/ConvolverOptions.h",
+  "$blink_modules_output_dir/webaudio/DelayOptions.cpp",
+  "$blink_modules_output_dir/webaudio/DelayOptions.h",
+  "$blink_modules_output_dir/webaudio/DynamicsCompressorOptions.cpp",
+  "$blink_modules_output_dir/webaudio/DynamicsCompressorOptions.h",
+  "$blink_modules_output_dir/webaudio/GainOptions.cpp",
+  "$blink_modules_output_dir/webaudio/GainOptions.h",
+  "$blink_modules_output_dir/webaudio/IIRFilterOptions.cpp",
+  "$blink_modules_output_dir/webaudio/IIRFilterOptions.h",
+  "$blink_modules_output_dir/webaudio/MediaElementAudioSourceOptions.cpp",
+  "$blink_modules_output_dir/webaudio/MediaElementAudioSourceOptions.h",
+  "$blink_modules_output_dir/webaudio/MediaStreamAudioSourceOptions.cpp",
+  "$blink_modules_output_dir/webaudio/MediaStreamAudioSourceOptions.h",
+  "$blink_modules_output_dir/webaudio/PannerOptions.cpp",
+  "$blink_modules_output_dir/webaudio/PannerOptions.h",
+  "$blink_modules_output_dir/webaudio/PeriodicWaveConstraints.cpp",
+  "$blink_modules_output_dir/webaudio/PeriodicWaveConstraints.h",
+  "$blink_modules_output_dir/webaudio/PeriodicWaveOptions.cpp",
+  "$blink_modules_output_dir/webaudio/PeriodicWaveOptions.h",
+  "$blink_modules_output_dir/webaudio/OfflineAudioCompletionEventInit.cpp",
+  "$blink_modules_output_dir/webaudio/OfflineAudioCompletionEventInit.h",
+  "$blink_modules_output_dir/webaudio/OscillatorOptions.cpp",
+  "$blink_modules_output_dir/webaudio/OscillatorOptions.h",
+  "$blink_modules_output_dir/webaudio/StereoPannerOptions.cpp",
+  "$blink_modules_output_dir/webaudio/StereoPannerOptions.h",
+  "$blink_modules_output_dir/webaudio/WaveShaperOptions.cpp",
+  "$blink_modules_output_dir/webaudio/WaveShaperOptions.h",
+  "$blink_modules_output_dir/webauth/RelyingPartyAccount.cpp",
+  "$blink_modules_output_dir/webauth/RelyingPartyAccount.h",
+  "$blink_modules_output_dir/webauth/AuthenticationAssertionOptions.cpp",
+  "$blink_modules_output_dir/webauth/AuthenticationAssertionOptions.h",
+  "$blink_modules_output_dir/webauth/AuthenticationClientData.cpp",
+  "$blink_modules_output_dir/webauth/AuthenticationClientData.h",
+  "$blink_modules_output_dir/webauth/ScopedCredentialDescriptor.cpp",
+  "$blink_modules_output_dir/webauth/ScopedCredentialDescriptor.h",
+  "$blink_modules_output_dir/webauth/ScopedCredentialOptions.cpp",
+  "$blink_modules_output_dir/webauth/ScopedCredentialOptions.h",
+  "$blink_modules_output_dir/webauth/ScopedCredentialParameters.cpp",
+  "$blink_modules_output_dir/webauth/ScopedCredentialParameters.h",
+  "$blink_modules_output_dir/webauth/AuthenticationExtensions.cpp",
+  "$blink_modules_output_dir/webauth/AuthenticationExtensions.h",
+  "$blink_modules_output_dir/webgl/WebGLContextAttributes.cpp",
+  "$blink_modules_output_dir/webgl/WebGLContextAttributes.h",
+  "$blink_modules_output_dir/webgl/WebGLContextEventInit.cpp",
+  "$blink_modules_output_dir/webgl/WebGLContextEventInit.h",
+  "$blink_modules_output_dir/webmidi/MIDIConnectionEventInit.cpp",
+  "$blink_modules_output_dir/webmidi/MIDIConnectionEventInit.h",
+  "$blink_modules_output_dir/webmidi/MIDIMessageEventInit.h",
+  "$blink_modules_output_dir/webmidi/MIDIMessageEventInit.cpp",
+  "$blink_modules_output_dir/webmidi/MIDIOptions.cpp",
+  "$blink_modules_output_dir/webmidi/MIDIOptions.h",
+  "$blink_modules_output_dir/webshare/ShareData.cpp",
+  "$blink_modules_output_dir/webshare/ShareData.h",
+  "$blink_modules_output_dir/websockets/CloseEventInit.cpp",
+  "$blink_modules_output_dir/websockets/CloseEventInit.h",
+  "$blink_modules_output_dir/webusb/USBConnectionEventInit.cpp",
+  "$blink_modules_output_dir/webusb/USBConnectionEventInit.h",
+  "$blink_modules_output_dir/webusb/USBControlTransferParameters.cpp",
+  "$blink_modules_output_dir/webusb/USBControlTransferParameters.h",
+  "$blink_modules_output_dir/webusb/USBDeviceFilter.cpp",
+  "$blink_modules_output_dir/webusb/USBDeviceFilter.h",
+  "$blink_modules_output_dir/webusb/USBDeviceRequestOptions.cpp",
+  "$blink_modules_output_dir/webusb/USBDeviceRequestOptions.h",
+]
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5 b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
index c9513942..c65986a 100644
--- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
+++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
@@ -542,6 +542,10 @@
       status: "stable",
     },
     {
+      name: "JSImageDecode",
+      status: "test",
+    },
+    {
       name: "KeyboardLock",
       status: "test",
     },
diff --git a/third_party/WebKit/Source/platform/loader/fetch/FetchContext.h b/third_party/WebKit/Source/platform/loader/fetch/FetchContext.h
index c6bc4fb..b0a2108 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/FetchContext.h
+++ b/third_party/WebKit/Source/platform/loader/fetch/FetchContext.h
@@ -213,6 +213,11 @@
     return nullptr;
   }
 
+  // Called when the underlying context is detached. Note that some
+  // FetchContexts continue working after detached (e.g., for fetch() operations
+  // with "keepalive" specified).
+  virtual void Detach() {}
+
  protected:
   FetchContext();
 
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.cpp b/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.cpp
index d0aa112..079c0ab 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.cpp
+++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.cpp
@@ -1189,6 +1189,7 @@
 
 void ResourceFetcher::ClearContext() {
   ClearPreloads(ResourceFetcher::kClearAllPreloads);
+  Context().Detach();
   context_.Clear();
 }
 
diff --git a/third_party/WebKit/Source/web/AssertMatchingEnums.cpp b/third_party/WebKit/Source/web/AssertMatchingEnums.cpp
index 2b563d6..7b74858 100644
--- a/third_party/WebKit/Source/web/AssertMatchingEnums.cpp
+++ b/third_party/WebKit/Source/web/AssertMatchingEnums.cpp
@@ -322,7 +322,6 @@
 STATIC_ASSERT_ENUM(kWebAXRoleWindow, kWindowRole);
 
 STATIC_ASSERT_ENUM(kWebAXStateBusy, kAXBusyState);
-STATIC_ASSERT_ENUM(kWebAXStateChecked, kAXCheckedState);
 STATIC_ASSERT_ENUM(kWebAXStateEnabled, kAXEnabledState);
 STATIC_ASSERT_ENUM(kWebAXStateExpanded, kAXExpandedState);
 STATIC_ASSERT_ENUM(kWebAXStateFocusable, kAXFocusableState);
@@ -334,7 +333,6 @@
 STATIC_ASSERT_ENUM(kWebAXStateMultiline, kAXMultilineState);
 STATIC_ASSERT_ENUM(kWebAXStateMultiselectable, kAXMultiselectableState);
 STATIC_ASSERT_ENUM(kWebAXStateOffscreen, kAXOffscreenState);
-STATIC_ASSERT_ENUM(kWebAXStatePressed, kAXPressedState);
 STATIC_ASSERT_ENUM(kWebAXStateProtected, kAXProtectedState);
 STATIC_ASSERT_ENUM(kWebAXStateReadonly, kAXReadonlyState);
 STATIC_ASSERT_ENUM(kWebAXStateRequired, kAXRequiredState);
diff --git a/third_party/WebKit/Source/web/ChromeClientImpl.cpp b/third_party/WebKit/Source/web/ChromeClientImpl.cpp
index 7a6cbf3..caec689 100644
--- a/third_party/WebKit/Source/web/ChromeClientImpl.cpp
+++ b/third_party/WebKit/Source/web/ChromeClientImpl.cpp
@@ -976,6 +976,15 @@
   return WebRemoteFrameImpl::FromFrame(frame);
 }
 
+void ChromeClientImpl::RequestDecode(
+    LocalFrame* frame,
+    sk_sp<SkImage> image,
+    std::unique_ptr<WTF::Function<void(bool)>> callback) {
+  WebLocalFrameImpl* web_frame = WebLocalFrameImpl::FromFrame(frame);
+  web_frame->LocalRoot()->FrameWidget()->RequestDecode(std::move(image),
+                                                       std::move(callback));
+}
+
 void ChromeClientImpl::SetEventListenerProperties(
     LocalFrame* frame,
     WebEventListenerClass event_class,
diff --git a/third_party/WebKit/Source/web/ChromeClientImpl.h b/third_party/WebKit/Source/web/ChromeClientImpl.h
index 20b7e22..c6d9fc2 100644
--- a/third_party/WebKit/Source/web/ChromeClientImpl.h
+++ b/third_party/WebKit/Source/web/ChromeClientImpl.h
@@ -240,6 +240,11 @@
 
   WebRemoteFrameBase* GetWebRemoteFrameBase(RemoteFrame&) override;
 
+  void RequestDecode(
+      LocalFrame*,
+      sk_sp<SkImage>,
+      std::unique_ptr<WTF::Function<void(bool)>> callback) override;
+
  private:
   explicit ChromeClientImpl(WebViewBase*);
 
diff --git a/third_party/WebKit/Source/web/ContextMenuClientImpl.cpp b/third_party/WebKit/Source/web/ContextMenuClientImpl.cpp
index 0870821..c3422ee 100644
--- a/third_party/WebKit/Source/web/ContextMenuClientImpl.cpp
+++ b/third_party/WebKit/Source/web/ContextMenuClientImpl.cpp
@@ -39,6 +39,7 @@
 #include "core/dom/ElementTraversal.h"
 #include "core/editing/Editor.h"
 #include "core/editing/markers/DocumentMarkerController.h"
+#include "core/editing/markers/SpellCheckMarker.h"
 #include "core/editing/spellcheck/SpellChecker.h"
 #include "core/exported/WebDataSourceImpl.h"
 #include "core/exported/WebPluginContainerBase.h"
@@ -144,7 +145,7 @@
   if (marker_it == markers_in_node.end())
     return String();
 
-  const DocumentMarker* const found_marker = *marker_it;
+  const SpellCheckMarker* const found_marker = ToSpellCheckMarker(*marker_it);
   description = found_marker->Description();
 
   Range* const marker_range =
diff --git a/third_party/WebKit/Source/web/WebAXObject.cpp b/third_party/WebKit/Source/web/WebAXObject.cpp
index 10a25fe1..3cbb779 100644
--- a/third_party/WebKit/Source/web/WebAXObject.cpp
+++ b/third_party/WebKit/Source/web/WebAXObject.cpp
@@ -285,16 +285,9 @@
   return static_cast<WebAXAriaCurrentState>(private_->GetAriaCurrentState());
 }
 
-bool WebAXObject::IsCheckable() const {
-  if (IsDetached())
-    return false;
-
-  return private_->IsCheckable();
-}
-
 WebAXCheckedState WebAXObject::CheckedState() const {
   if (IsDetached())
-    return WebAXCheckedFalse;
+    return kWebAXCheckedUndefined;
 
   return static_cast<WebAXCheckedState>(private_->CheckedState());
 }
@@ -390,13 +383,6 @@
   return private_->IsPasswordField();
 }
 
-bool WebAXObject::IsPressed() const {
-  if (IsDetached())
-    return false;
-
-  return private_->IsPressed();
-}
-
 bool WebAXObject::IsReadOnly() const {
   if (IsDetached())
     return false;
diff --git a/third_party/WebKit/Source/web/WebViewImpl.cpp b/third_party/WebKit/Source/web/WebViewImpl.cpp
index f2d32a8..25ac509 100644
--- a/third_party/WebKit/Source/web/WebViewImpl.cpp
+++ b/third_party/WebKit/Source/web/WebViewImpl.cpp
@@ -3503,6 +3503,13 @@
   return local_frame ? local_frame->GetInputMethodController() : nullptr;
 }
 
+void WebViewImpl::RequestDecode(
+    sk_sp<SkImage> image,
+    std::unique_ptr<WTF::Function<void(bool)>> callback) {
+  layer_tree_view_->RequestDecode(std::move(image),
+                                  ConvertToBaseCallback(std::move(callback)));
+}
+
 Color WebViewImpl::BaseBackgroundColor() const {
   return base_background_color_override_enabled_
              ? base_background_color_override_
diff --git a/third_party/WebKit/Source/web/WebViewImpl.h b/third_party/WebKit/Source/web/WebViewImpl.h
index 40e1e6a..8aa59e5 100644
--- a/third_party/WebKit/Source/web/WebViewImpl.h
+++ b/third_party/WebKit/Source/web/WebViewImpl.h
@@ -507,6 +507,10 @@
     last_hidden_page_popup_ = page_popup;
   }
 
+  void RequestDecode(
+      sk_sp<SkImage>,
+      std::unique_ptr<WTF::Function<void(bool)>> callback) override;
+
  private:
   void SetPageScaleFactorAndLocation(float, const FloatPoint&);
   void PropagateZoomFactorToLocalFrameRoots(Frame*, float);
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_expectations_updater.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_expectations_updater.py
index bac29bc..2d7e7404 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_expectations_updater.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_expectations_updater.py
@@ -30,7 +30,7 @@
         self.host = host
         self.port = self.host.port_factory.get()
         self.finder = PathFinder(self.host.filesystem)
-        self.port = self.host.port_factory.get()
+        self.ports_with_no_results = set()
 
     def run(self, args=None):
         """Downloads text new baselines and adds test expectations lines."""
@@ -101,10 +101,11 @@
             this will return an empty dictionary.
         """
         layout_test_results = self.host.buildbot.fetch_results(build)
+        port_name = self.host.builders.port_name_for_builder_name(build.builder_name)
         if layout_test_results is None:
             _log.warning('No results for build %s', build)
+            self.ports_with_no_results.add(port_name)
             return {}
-        port_name = self.host.builders.port_name_for_builder_name(build.builder_name)
         test_results = [result for result in layout_test_results.didnt_run_as_expected_results() if not result.did_pass()]
         failing_results_dict = self.generate_results_dict(port_name, test_results)
         return failing_results_dict
@@ -274,9 +275,23 @@
         return line_list
 
     def _create_line(self, test_name, port_names, results):
-        """Constructs one test expectations line string."""
+        """Constructs and returns a test expectation line string."""
+        port_names = self.tuple_or_value_to_list(port_names)
+
+        # The set of ports with no results is assumed to have have no
+        # overlap with the set of port names passed in here.
+        assert (set(port_names) & self.ports_with_no_results) == set()
+
+        # The ports with no results are generally ports of builders that
+        # failed, maybe for unrelated reasons. At this point, we add ports
+        # with no results to the list of platforms because we're guessing
+        # that this new expectation might be cross-platform and should
+        # also apply to any ports that we weren't able to get results for.
+        port_names.extend(self.ports_with_no_results)
+
+        specifier_part = self.specifier_part(port_names, test_name)
+
         line_parts = [results['bug']]
-        specifier_part = self.specifier_part(self.to_list(port_names), test_name)
         if specifier_part:
             line_parts.append(specifier_part)
         line_parts.append(test_name)
@@ -306,7 +321,7 @@
         return '[ %s ]' % ' '.join(specifiers)
 
     @staticmethod
-    def to_list(tuple_or_value):
+    def tuple_or_value_to_list(tuple_or_value):
         """Converts a tuple to a list, and a string value to a one-item list."""
         if isinstance(tuple_or_value, tuple):
             return list(tuple_or_value)
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_expectations_updater_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_expectations_updater_unittest.py
index 4dd0d76..7d50715 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_expectations_updater_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_expectations_updater_unittest.py
@@ -515,3 +515,24 @@
         self.assertEqual(
             updater.create_line_list(results),
             ['crbug.com/test external/wpt/x-manual.html [ Skip ]'])
+
+    def test_one_platform_has_no_results(self):
+        # In this example, there is a failure that has been observed on
+        # Linux and one Mac port, but the other Mac port has no results at all.
+        # The specifiers are "filled in" and the failure is assumed to apply
+        # to all Mac platforms.
+        host = self.mock_host()
+        updater = WPTExpectationsUpdater(host)
+        results = {
+            'external/wpt/x.html': {
+                (
+                    'test-linux-precise',
+                    'test-linux-trusty',
+                    'test-mac-mac10.11',
+                ): {'expected': 'PASS', 'actual': 'TEXT', 'bug': 'crbug.com/test'}
+            }
+        }
+        updater.ports_with_no_results = {'test-mac-mac10.10'}
+        self.assertEqual(
+            updater.create_line_list(results),
+            ['crbug.com/test [ Linux Mac ] external/wpt/x.html [ Failure ]'])
diff --git a/third_party/WebKit/public/platform/WebLayerTreeView.h b/third_party/WebKit/public/platform/WebLayerTreeView.h
index 494c896..a26fc58 100644
--- a/third_party/WebKit/public/platform/WebLayerTreeView.h
+++ b/third_party/WebKit/public/platform/WebLayerTreeView.h
@@ -36,6 +36,9 @@
 #include "base/callback.h"
 #include "cc/surfaces/frame_sink_id.h"
 
+#include "third_party/skia/include/core/SkImage.h"
+#include "third_party/skia/include/core/SkRefCnt.h"
+
 namespace cc {
 class AnimationHost;
 }
@@ -190,6 +193,9 @@
   // ReportTimeCallback is a callback that should be fired when the
   // corresponding Swap completes (either with DidSwap or DidNotSwap).
   virtual void NotifySwapTime(ReportTimeCallback callback) {}
+
+  virtual void RequestDecode(sk_sp<SkImage> image,
+                             const base::Callback<void(bool)>& callback) {}
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/public/web/WebAXEnums.h b/third_party/WebKit/public/web/WebAXEnums.h
index 5814a350..23d5cf7 100644
--- a/third_party/WebKit/public/web/WebAXEnums.h
+++ b/third_party/WebKit/public/web/WebAXEnums.h
@@ -206,7 +206,6 @@
 // Accessibility states, used as a bitmask.
 enum WebAXState {
   kWebAXStateBusy,
-  kWebAXStateChecked,
   kWebAXStateEnabled,
   kWebAXStateExpanded,
   kWebAXStateFocusable,
@@ -218,7 +217,6 @@
   kWebAXStateMultiline,
   kWebAXStateMultiselectable,
   kWebAXStateOffscreen,
-  kWebAXStatePressed,
   kWebAXStateProtected,
   kWebAXStateReadonly,
   kWebAXStateRequired,
@@ -258,9 +256,10 @@
 };
 
 enum WebAXCheckedState {
-  WebAXCheckedFalse = 0,
-  WebAXCheckedTrue,
-  WebAXCheckedMixed
+  kWebAXCheckedUndefined = 0,
+  kWebAXCheckedFalse,
+  kWebAXCheckedTrue,
+  kWebAXCheckedMixed
 };
 
 // Expanded State.
diff --git a/third_party/WebKit/public/web/WebAXObject.h b/third_party/WebKit/public/web/WebAXObject.h
index 8565c87f..12c1545b 100644
--- a/third_party/WebKit/public/web/WebAXObject.h
+++ b/third_party/WebKit/public/web/WebAXObject.h
@@ -149,7 +149,6 @@
   BLINK_EXPORT bool IsMultiSelectable() const;
   BLINK_EXPORT bool IsOffScreen() const;
   BLINK_EXPORT bool IsPasswordField() const;
-  BLINK_EXPORT bool IsPressed() const;
   BLINK_EXPORT bool IsReadOnly() const;
   BLINK_EXPORT bool IsRequired() const;
   BLINK_EXPORT bool IsSelected() const;
diff --git a/third_party/opus/README.chromium b/third_party/opus/README.chromium
index 7111d02..bf56abc 100644
--- a/third_party/opus/README.chromium
+++ b/third_party/opus/README.chromium
@@ -18,3 +18,4 @@
   https://git.xiph.org/?p=opus.git;a=commit;h=79e8f527b0344b0897a65be35e77f7885bd99409
   https://git.xiph.org/?p=opus.git;a=commitdiff;h=e5ad26169502c1f0b067916e782c2b3fdea6fba9
   https://git.xiph.org/?p=opus.git;a=commitdiff;h=5da0498a3e23339aaceba659a97e935031d5693d
+  https://git.xiph.org/?p=opus.git;a=commitdiff;h=8d02afe05b80097f5a09361bb75e2950cb3ea6e2
diff --git a/third_party/opus/src/src/opus_multistream_encoder.c b/third_party/opus/src/src/opus_multistream_encoder.c
index e722e31..1698223 100644
--- a/third_party/opus/src/src/opus_multistream_encoder.c
+++ b/third_party/opus/src/src/opus_multistream_encoder.c
@@ -277,7 +277,7 @@
          sum = celt_inner_prod(in, in, frame_size+overlap, 0);
          /* This should filter out both NaNs and ridiculous signals that could
             cause NaNs further down. */
-         if (!(sum < 1e9f) || celt_isnan(sum))
+         if (!(sum < 1e18f) || celt_isnan(sum))
          {
             OPUS_CLEAR(in, frame_size+overlap);
             preemph_mem[c] = 0;
diff --git a/third_party/wayland-protocols/include/protocol/remote-shell-unstable-v1-client-protocol.h b/third_party/wayland-protocols/include/protocol/remote-shell-unstable-v1-client-protocol.h
index 7b3daa9..9974176 100644
--- a/third_party/wayland-protocols/include/protocol/remote-shell-unstable-v1-client-protocol.h
+++ b/third_party/wayland-protocols/include/protocol/remote-shell-unstable-v1-client-protocol.h
@@ -259,15 +259,16 @@
 				      int32_t work_area_inset_right,
 				      int32_t work_area_inset_bottom,
 				      uint32_t layout_mode);
-        /**
-         * area of remote shell
-         *
-         * Defines an area of the remote shell used for layout. Each
-         * series of "workspace" events must be terminated by a "configure"
-         * event.
-         * @since 5
-         */
-        void (*workspace)(void *data,
+	/**
+	 * area of remote shell
+	 *
+	 * Defines an area of the remote shell used for layout. Each
+	 * series of "workspace" events must be terminated by a "configure"
+	 * event.
+	 * @param is_internal 1 if screen is built-in
+	 * @since 5
+	 */
+	void (*workspace)(void *data,
 			  struct zcr_remote_shell_v1 *zcr_remote_shell_v1,
 			  uint32_t id_hi,
 			  uint32_t id_lo,
@@ -280,15 +281,16 @@
 			  int32_t inset_right,
 			  int32_t inset_bottom,
 			  int32_t transform,
-			  wl_fixed_t scale_factor);
-        /**
-         * suggests configuration of remote shell
-         *
-         * Suggests a new configuration of the remote shell. Preceded by
-         * a series of "workspace" events.
-         * @since 5
-         */
-        void (*configure)(void *data,
+			  wl_fixed_t scale_factor,
+			  uint32_t is_internal);
+	/**
+	 * suggests configuration of remote shell
+	 *
+	 * Suggests a new configuration of the remote shell. Preceded by
+	 * a series of "workspace" events.
+	 * @since 5
+	 */
+	void (*configure)(void *data,
 			  struct zcr_remote_shell_v1 *zcr_remote_shell_v1,
 			  uint32_t layout_mode);
 };
@@ -425,18 +427,18 @@
  * Determine the visibility behavior of the system UI.
  */
 enum zcr_remote_surface_v1_systemui_visibility_state {
-  /**
-   * system ui is visible
-   */
-  ZCR_REMOTE_SURFACE_V1_SYSTEMUI_VISIBILITY_STATE_VISIBLE = 1,
-  /**
-   * system ui autohides and is not sticky
-   */
-  ZCR_REMOTE_SURFACE_V1_SYSTEMUI_VISIBILITY_STATE_AUTOHIDE_NON_STICKY = 2,
-  /**
-   * system ui autohides and is sticky
-   */
-  ZCR_REMOTE_SURFACE_V1_SYSTEMUI_VISIBILITY_STATE_AUTOHIDE_STICKY = 3,
+	/**
+	 * system ui is visible
+	 */
+	ZCR_REMOTE_SURFACE_V1_SYSTEMUI_VISIBILITY_STATE_VISIBLE = 1,
+	/**
+	 * system ui autohides and is not sticky
+	 */
+	ZCR_REMOTE_SURFACE_V1_SYSTEMUI_VISIBILITY_STATE_AUTOHIDE_NON_STICKY = 2,
+	/**
+	 * system ui autohides and is sticky
+	 */
+	ZCR_REMOTE_SURFACE_V1_SYSTEMUI_VISIBILITY_STATE_AUTOHIDE_STICKY = 3,
 };
 #endif /* ZCR_REMOTE_SURFACE_V1_SYSTEMUI_VISIBILITY_STATE_ENUM */
 
@@ -473,28 +475,28 @@
 	void (*state_type_changed)(void *data,
 				   struct zcr_remote_surface_v1 *zcr_remote_surface_v1,
 				   uint32_t state_type);
-        /**
-         * suggest a surface change
-         *
-         * The configure event asks the client to change surface state.
-         *
-         * The client must apply the origin offset to window positions in
-         * set_window_geometry requests.
-         *
-         * The states listed in the event are state_type values, and might
-         * change due to a client request or an event directly handled by
-         * the compositor.
-         *
-         * Clients should arrange their surface for the new state, and then
-         * send an ack_configure request with the serial sent in this
-         * configure event at some point before committing the new surface.
-         *
-         * If the client receives multiple configure events before it can
-         * respond to one, it is free to discard all but the last event it
-         * received.
-         * @since 5
-         */
-        void (*configure)(void *data,
+	/**
+	 * suggest a surface change
+	 *
+	 * The configure event asks the client to change surface state.
+	 *
+	 * The client must apply the origin offset to window positions in
+	 * set_window_geometry requests.
+	 *
+	 * The states listed in the event are state_type values, and might
+	 * change due to a client request or an event directly handled by
+	 * the compositor.
+	 *
+	 * Clients should arrange their surface for the new state, and then
+	 * send an ack_configure request with the serial sent in this
+	 * configure event at some point before committing the new surface.
+	 *
+	 * If the client receives multiple configure events before it can
+	 * respond to one, it is free to discard all but the last event it
+	 * received.
+	 * @since 5
+	 */
+	void (*configure)(void *data,
 			  struct zcr_remote_surface_v1 *zcr_remote_surface_v1,
 			  int32_t origin_offset_x,
 			  int32_t origin_offset_y,
@@ -983,14 +985,13 @@
 /**
  * @ingroup iface_zcr_remote_surface_v1
  *
- * Requests how the surface will change the visibility of the system UI when it
- * is made active.
+ * Requests how the surface will change the visibility of the system UI when it is made active.
  */
-static inline void zcr_remote_surface_v1_set_systemui_visibility(
-    struct zcr_remote_surface_v1* zcr_remote_surface_v1,
-    uint32_t visibility) {
-  wl_proxy_marshal((struct wl_proxy*)zcr_remote_surface_v1,
-                   ZCR_REMOTE_SURFACE_V1_SET_SYSTEMUI_VISIBILITY, visibility);
+static inline void
+zcr_remote_surface_v1_set_systemui_visibility(struct zcr_remote_surface_v1 *zcr_remote_surface_v1, uint32_t visibility)
+{
+	wl_proxy_marshal((struct wl_proxy *) zcr_remote_surface_v1,
+			 ZCR_REMOTE_SURFACE_V1_SET_SYSTEMUI_VISIBILITY, visibility);
 }
 
 /**
@@ -1002,10 +1003,11 @@
  * The compositor may choose to ignore this request.
  *
  */
-static inline void zcr_remote_surface_v1_set_always_on_top(
-    struct zcr_remote_surface_v1* zcr_remote_surface_v1) {
-  wl_proxy_marshal((struct wl_proxy*)zcr_remote_surface_v1,
-                   ZCR_REMOTE_SURFACE_V1_SET_ALWAYS_ON_TOP);
+static inline void
+zcr_remote_surface_v1_set_always_on_top(struct zcr_remote_surface_v1 *zcr_remote_surface_v1)
+{
+	wl_proxy_marshal((struct wl_proxy *) zcr_remote_surface_v1,
+			 ZCR_REMOTE_SURFACE_V1_SET_ALWAYS_ON_TOP);
 }
 
 /**
@@ -1016,10 +1018,11 @@
  * This is only a request that the window should be not always on top.
  * The compositor may choose to ignore this request.
  */
-static inline void zcr_remote_surface_v1_unset_always_on_top(
-    struct zcr_remote_surface_v1* zcr_remote_surface_v1) {
-  wl_proxy_marshal((struct wl_proxy*)zcr_remote_surface_v1,
-                   ZCR_REMOTE_SURFACE_V1_UNSET_ALWAYS_ON_TOP);
+static inline void
+zcr_remote_surface_v1_unset_always_on_top(struct zcr_remote_surface_v1 *zcr_remote_surface_v1)
+{
+	wl_proxy_marshal((struct wl_proxy *) zcr_remote_surface_v1,
+			 ZCR_REMOTE_SURFACE_V1_UNSET_ALWAYS_ON_TOP);
 }
 
 /**
diff --git a/third_party/wayland-protocols/include/protocol/remote-shell-unstable-v1-server-protocol.h b/third_party/wayland-protocols/include/protocol/remote-shell-unstable-v1-server-protocol.h
index 79a014b..bd16496 100644
--- a/third_party/wayland-protocols/include/protocol/remote-shell-unstable-v1-server-protocol.h
+++ b/third_party/wayland-protocols/include/protocol/remote-shell-unstable-v1-server-protocol.h
@@ -340,11 +340,12 @@
  * @ingroup iface_zcr_remote_shell_v1
  * Sends an workspace event to the client owning the resource.
  * @param resource_ The client's resource
+ * @param is_internal 1 if screen is built-in
  */
 static inline void
-zcr_remote_shell_v1_send_workspace(struct wl_resource *resource_, uint32_t id_hi, uint32_t id_lo, int32_t x, int32_t y, int32_t width, int32_t height, int32_t inset_left, int32_t inset_top, int32_t inset_right, int32_t inset_bottom, int32_t transform, wl_fixed_t scale_factor)
+zcr_remote_shell_v1_send_workspace(struct wl_resource *resource_, uint32_t id_hi, uint32_t id_lo, int32_t x, int32_t y, int32_t width, int32_t height, int32_t inset_left, int32_t inset_top, int32_t inset_right, int32_t inset_bottom, int32_t transform, wl_fixed_t scale_factor, uint32_t is_internal)
 {
-	wl_resource_post_event(resource_, ZCR_REMOTE_SHELL_V1_WORKSPACE, id_hi, id_lo, x, y, width, height, inset_left, inset_top, inset_right, inset_bottom, transform, scale_factor);
+	wl_resource_post_event(resource_, ZCR_REMOTE_SHELL_V1_WORKSPACE, id_hi, id_lo, x, y, width, height, inset_left, inset_top, inset_right, inset_bottom, transform, scale_factor, is_internal);
 }
 
 /**
@@ -367,18 +368,18 @@
  * Determine the visibility behavior of the system UI.
  */
 enum zcr_remote_surface_v1_systemui_visibility_state {
-  /**
-   * system ui is visible
-   */
-  ZCR_REMOTE_SURFACE_V1_SYSTEMUI_VISIBILITY_STATE_VISIBLE = 1,
-  /**
-   * system ui autohides and is not sticky
-   */
-  ZCR_REMOTE_SURFACE_V1_SYSTEMUI_VISIBILITY_STATE_AUTOHIDE_NON_STICKY = 2,
-  /**
-   * system ui autohides and is sticky
-   */
-  ZCR_REMOTE_SURFACE_V1_SYSTEMUI_VISIBILITY_STATE_AUTOHIDE_STICKY = 3,
+	/**
+	 * system ui is visible
+	 */
+	ZCR_REMOTE_SURFACE_V1_SYSTEMUI_VISIBILITY_STATE_VISIBLE = 1,
+	/**
+	 * system ui autohides and is not sticky
+	 */
+	ZCR_REMOTE_SURFACE_V1_SYSTEMUI_VISIBILITY_STATE_AUTOHIDE_NON_STICKY = 2,
+	/**
+	 * system ui autohides and is sticky
+	 */
+	ZCR_REMOTE_SURFACE_V1_SYSTEMUI_VISIBILITY_STATE_AUTOHIDE_STICKY = 3,
 };
 #endif /* ZCR_REMOTE_SURFACE_V1_SYSTEMUI_VISIBILITY_STATE_ENUM */
 
@@ -631,85 +632,86 @@
 					       int32_t y,
 					       int32_t width,
 					       int32_t height);
-        /**
-         * requests the system ui visibility behavior for the surface
-         *
-         * Requests how the surface will change the visibility of the
-         * system UI when it is made active.
-         * @since 3
-         */
-        void (*set_systemui_visibility)(struct wl_client* client,
-                                        struct wl_resource* resource,
-                                        uint32_t visibility);
-        /**
-         * set always on top
-         *
-         * Request that surface is made to be always on top.
-         *
-         * This is only a request that the window should be always on top.
-         * The compositor may choose to ignore this request.
-         * @since 4
-         */
-        void (*set_always_on_top)(struct wl_client* client,
-                                  struct wl_resource* resource);
-        /**
-         * unset always on top
-         *
-         * Request that surface is made to be not always on top.
-         *
-         * This is only a request that the window should be not always on
-         * top. The compositor may choose to ignore this request.
-         * @since 4
-         */
-        void (*unset_always_on_top)(struct wl_client* client,
-                                    struct wl_resource* resource);
-        /**
-         * ack a configure event
-         *
-         * When a configure event is received, if a client commits the
-         * surface in response to the configure event, then the client must
-         * make an ack_configure request sometime before the commit
-         * request, passing along the serial of the configure event.
-         *
-         * For instance, the compositor might use this information during
-         * display configuration to change its coordinate space for
-         * set_window_geometry requests only when the client has switched
-         * to the new coordinate space.
-         *
-         * If the client receives multiple configure events before it can
-         * respond to one, it only has to ack the last configure event.
-         *
-         * A client is not required to commit immediately after sending an
-         * ack_configure request - it may even ack_configure several times
-         * before its next surface commit.
-         *
-         * A client may send multiple ack_configure requests before
-         * committing, but only the last request sent before a commit
-         * indicates which configure event the client really is responding
-         * to.
-         * @param serial the serial from the configure event
-         * @since 5
-         */
-        void (*ack_configure)(struct wl_client* client,
-                              struct wl_resource* resource,
-                              uint32_t serial);
-        /**
-         * start an interactive move
-         *
-         * Start an interactive, user-driven move of the surface.
-         *
-         * The compositor responds to this request with a configure event
-         * that transitions to the "moving" state. The client must only
-         * initiate motion after acknowledging the state change. The
-         * compositor can assume that subsequent set_window_geometry
-         * requests are position updates until the next state transition is
-         * acknowledged.
-         *
-         * The compositor may ignore move requests depending on the state
-         * of the surface, e.g. fullscreen or maximized.
-         * @since 5
-         */
-        void (*move)(struct wl_client* client, struct wl_resource* resource);
+	/**
+	 * requests the system ui visibility behavior for the surface
+	 *
+	 * Requests how the surface will change the visibility of the
+	 * system UI when it is made active.
+	 * @since 3
+	 */
+	void (*set_systemui_visibility)(struct wl_client *client,
+					struct wl_resource *resource,
+					uint32_t visibility);
+	/**
+	 * set always on top
+	 *
+	 * Request that surface is made to be always on top.
+	 *
+	 * This is only a request that the window should be always on top.
+	 * The compositor may choose to ignore this request.
+	 * @since 4
+	 */
+	void (*set_always_on_top)(struct wl_client *client,
+				  struct wl_resource *resource);
+	/**
+	 * unset always on top
+	 *
+	 * Request that surface is made to be not always on top.
+	 *
+	 * This is only a request that the window should be not always on
+	 * top. The compositor may choose to ignore this request.
+	 * @since 4
+	 */
+	void (*unset_always_on_top)(struct wl_client *client,
+				    struct wl_resource *resource);
+	/**
+	 * ack a configure event
+	 *
+	 * When a configure event is received, if a client commits the
+	 * surface in response to the configure event, then the client must
+	 * make an ack_configure request sometime before the commit
+	 * request, passing along the serial of the configure event.
+	 *
+	 * For instance, the compositor might use this information during
+	 * display configuration to change its coordinate space for
+	 * set_window_geometry requests only when the client has switched
+	 * to the new coordinate space.
+	 *
+	 * If the client receives multiple configure events before it can
+	 * respond to one, it only has to ack the last configure event.
+	 *
+	 * A client is not required to commit immediately after sending an
+	 * ack_configure request - it may even ack_configure several times
+	 * before its next surface commit.
+	 *
+	 * A client may send multiple ack_configure requests before
+	 * committing, but only the last request sent before a commit
+	 * indicates which configure event the client really is responding
+	 * to.
+	 * @param serial the serial from the configure event
+	 * @since 5
+	 */
+	void (*ack_configure)(struct wl_client *client,
+			      struct wl_resource *resource,
+			      uint32_t serial);
+	/**
+	 * start an interactive move
+	 *
+	 * Start an interactive, user-driven move of the surface.
+	 *
+	 * The compositor responds to this request with a configure event
+	 * that transitions to the "moving" state. The client must only
+	 * initiate motion after acknowledging the state change. The
+	 * compositor can assume that subsequent set_window_geometry
+	 * requests are position updates until the next state transition is
+	 * acknowledged.
+	 *
+	 * The compositor may ignore move requests depending on the state
+	 * of the surface, e.g. fullscreen or maximized.
+	 * @since 5
+	 */
+	void (*move)(struct wl_client *client,
+		     struct wl_resource *resource);
 };
 
 #define ZCR_REMOTE_SURFACE_V1_CLOSE 0
diff --git a/third_party/wayland-protocols/protocol/remote-shell-protocol.c b/third_party/wayland-protocols/protocol/remote-shell-protocol.c
index 6aa75fa..316ed59 100644
--- a/third_party/wayland-protocols/protocol/remote-shell-protocol.c
+++ b/third_party/wayland-protocols/protocol/remote-shell-protocol.c
@@ -44,6 +44,7 @@
 	NULL,
 	NULL,
 	NULL,
+	NULL,
 	&zcr_remote_surface_v1_interface,
 	&wl_surface_interface,
 	NULL,
@@ -56,14 +57,14 @@
 
 static const struct wl_message zcr_remote_shell_v1_requests[] = {
 	{ "destroy", "", types + 0 },
-	{ "get_remote_surface", "nou", types + 12 },
-	{ "get_notification_surface", "nos", types + 15 },
+	{ "get_remote_surface", "nou", types + 13 },
+	{ "get_notification_surface", "nos", types + 16 },
 };
 
 static const struct wl_message zcr_remote_shell_v1_events[] = {
-	{ "activated", "?o?o", types + 18 },
+	{ "activated", "?o?o", types + 19 },
 	{ "configuration_changed", "iiifiiiiu", types + 0 },
-	{ "workspace", "5uuiiiiiiiiif", types + 0 },
+	{ "workspace", "5uuiiiiiiiiifu", types + 0 },
 	{ "configure", "5u", types + 0 },
 };
 
diff --git a/third_party/wayland-protocols/unstable/remote-shell/remote-shell-unstable-v1.xml b/third_party/wayland-protocols/unstable/remote-shell/remote-shell-unstable-v1.xml
index 9542dec..d15355d 100644
--- a/third_party/wayland-protocols/unstable/remote-shell/remote-shell-unstable-v1.xml
+++ b/third_party/wayland-protocols/unstable/remote-shell/remote-shell-unstable-v1.xml
@@ -159,6 +159,7 @@
       <arg name="inset_bottom" type="int"/>
       <arg name="transform" type="int"/>
       <arg name="scale_factor" type="fixed"/>
+      <arg name="is_internal" type="uint" summary="1 if screen is built-in"/>
     </event>
 
     <event name="configure" since="5">
diff --git a/tools/chrome_proxy/webdriver/smoke.py b/tools/chrome_proxy/webdriver/smoke.py
index ff99fdf..2aa896b8 100644
--- a/tools/chrome_proxy/webdriver/smoke.py
+++ b/tools/chrome_proxy/webdriver/smoke.py
@@ -19,9 +19,38 @@
       t.AddChromeArg('--enable-spdy-proxy-auth')
       t.AddChromeArg('--incognito')
       t.LoadURL('http://check.googlezip.net/test.html')
-      for response in t.GetHTTPResponses():
+      responses = t.GetHTTPResponses()
+      self.assertNotEqual(0, len(responses))
+      for response in responses:
         self.assertNotHasChromeProxyViaHeader(response)
 
+  # Ensure Chrome does not use DataSaver when holdback is enabled.
+  def testCheckPageWithHoldback(self):
+    with TestDriver() as t:
+      t.AddChromeArg('--enable-spdy-proxy-auth')
+      t.AddChromeArg('--force-fieldtrials=DataCompressionProxyHoldback/'
+                               'Enabled')
+      t.LoadURL('http://check.googlezip.net/test.html')
+      responses = t.GetHTTPResponses()
+      self.assertNotEqual(0, len(responses))
+      num_chrome_proxy_request_headers = 0
+      for response in responses:
+        self.assertNotHasChromeProxyViaHeader(response)
+        if ('chrome-proxy' in response.request_headers):
+          num_chrome_proxy_request_headers += 1
+      # DataSaver histograms must still be logged.
+      t.SleepUntilHistogramHasEntry('PageLoad.Clients.DataReductionProxy.'
+              'ParseTiming.NavigationToParseStart')
+      self.assertEqual(num_chrome_proxy_request_headers, 0)
+      # Ensure that Chrome did not attempt to use DataSaver and got a bypass.
+      histogram = t.GetHistogram('DataReductionProxy.BypassedBytes.'
+        'Status502HttpBadGateway', 5)
+      self.assertEqual(histogram, {})
+      histogram = t.GetHistogram('DataReductionProxy.BlockTypePrimary', 5)
+      self.assertEqual(histogram, {})
+      histogram = t.GetHistogram('DataReductionProxy.BypassTypePrimary', 5)
+      self.assertEqual(histogram, {})
+
   # Ensure Chrome uses DataSaver in normal mode.
   def testCheckPageWithNormalMode(self):
     with TestDriver() as t:
@@ -29,8 +58,14 @@
       t.LoadURL('http://check.googlezip.net/test.html')
       responses = t.GetHTTPResponses()
       self.assertNotEqual(0, len(responses))
+      num_chrome_proxy_request_headers = 0
       for response in responses:
         self.assertHasChromeProxyViaHeader(response)
+        if ('chrome-proxy' in response.request_headers):
+          num_chrome_proxy_request_headers += 1
+      t.SleepUntilHistogramHasEntry('PageLoad.Clients.DataReductionProxy.'
+        'ParseTiming.NavigationToParseStart')
+      self.assertGreater(num_chrome_proxy_request_headers, 0)
 
   # Ensure pageload metric pingback with DataSaver.
   def testPingback(self):
diff --git a/tools/chrome_proxy/webdriver/variations_combinations.py b/tools/chrome_proxy/webdriver/variations_combinations.py
index 83715059..20c565ac 100644
--- a/tools/chrome_proxy/webdriver/variations_combinations.py
+++ b/tools/chrome_proxy/webdriver/variations_combinations.py
@@ -17,11 +17,12 @@
 
 test_blacklist = [
   # These tests set their own field trials and should be ignored.
+  'lite_page.LitePage.testLitePageFallback',
   'lofi.LoFi.testLoFiSlowConnection',
   'lofi.LoFi.testLoFiIfHeavyFastConnection',
   'quic.Quic.testCheckPageWithQuicProxy',
   'quic.Quic.testCheckPageWithQuicProxyTransaction',
-  'lite_page.LitePage.testLitePageFallback',
+  'smoke.Smoke.testCheckPageWithHoldback',
 ]
 
 def GetExperimentArgs():
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 87b3bf4..dcfc5ee0 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -21587,6 +21587,7 @@
       label="CrossOriginMediaPlaybackRequiresUserGesture:enabled"/>
   <int value="-2099035488" label="enable-data-reduction-proxy-bypass-warning"/>
   <int value="-2098610409" label="disable-lcd-text"/>
+  <int value="-2098243118" label="OmniboxTailSuggestions:disabled"/>
   <int value="-2097515669" label="disable-cast"/>
   <int value="-2091404586" label="TabStripKeyboardFocus:enabled"/>
   <int value="-2090484194" label="ContextualSearchUrlActions:disabled"/>
@@ -22321,6 +22322,7 @@
   <int value="504994663" label="GenericSensor:disabled"/>
   <int value="506680761" label="WebNFC:disabled"/>
   <int value="510814146" label="OfflineBookmarks:enabled"/>
+  <int value="535131384" label="OmniboxTailSuggestions:enabled"/>
   <int value="535976218" label="enable-plugin-power-saver"/>
   <int value="538468149" label="OfflinePagesCT:enabled"/>
   <int value="546520086" label="enable-data-reduction-proxy-savings-promo"/>
diff --git a/tools/perf/benchmarks/system_health.py b/tools/perf/benchmarks/system_health.py
index b963e6d1..1e4bd53b8 100644
--- a/tools/perf/benchmarks/system_health.py
+++ b/tools/perf/benchmarks/system_health.py
@@ -72,6 +72,9 @@
   def Name(cls):
     return 'system_health.common_desktop'
 
+  def GetExpectations(self):
+    return page_sets.SystemHealthDesktopCommonExpectations()
+
 
 @benchmark.Enabled('android')
 @benchmark.Owner(emails=['charliea@chromium.org', 'nednguyen@chromium.org'])
@@ -83,6 +86,9 @@
   def Name(cls):
     return 'system_health.common_mobile'
 
+  def GetExpectations(self):
+    return page_sets.SystemHealthMobileCommonExpectations()
+
 
 class _MemorySystemHealthBenchmark(perf_benchmark.PerfBenchmark):
   """Chrome Memory System Health Benchmark.
@@ -133,6 +139,9 @@
   def Name(cls):
     return 'system_health.memory_desktop'
 
+  def GetExpectations(self):
+    return page_sets.SystemHealthDesktopMemoryExpectations()
+
 
 @benchmark.Enabled('android')
 @benchmark.Owner(emails=['perezju@chromium.org'])
@@ -153,6 +162,9 @@
   def Name(cls):
     return 'system_health.memory_mobile'
 
+  def GetExpectations(self):
+    return page_sets.SystemHealthMobileMemoryExpectations()
+
 
 @benchmark.Enabled('android-webview')
 @benchmark.Owner(emails=['perezju@chromium.org', 'torne@chromium.org'])
@@ -169,6 +181,9 @@
   def CreateStorySet(self, options):
     return page_sets.SystemHealthBlankStorySet()
 
+  def GetExpectations(self):
+    return page_sets.SystemHealthWebviewStartupExpectations()
+
   def CreateTimelineBasedMeasurementOptions(self):
     options = timeline_based_measurement.Options()
     options.SetTimelineBasedMetrics(['webviewStartupMetric'])
diff --git a/tools/perf/benchmarks/v8_browsing.py b/tools/perf/benchmarks/v8_browsing.py
index 67d48bbc..6e1defa 100644
--- a/tools/perf/benchmarks/v8_browsing.py
+++ b/tools/perf/benchmarks/v8_browsing.py
@@ -74,6 +74,14 @@
   def CreateStorySet(self, options):
     return page_sets.SystemHealthStorySet(platform=self.PLATFORM, case='browse')
 
+  def GetExpectations(self):
+    if self.PLATFORM is 'desktop':
+      return page_sets.V8BrowsingDesktopExpecations()
+    if self.PLATFORM is 'mobile':
+      return page_sets.V8BrowsingMobileExpecations()
+    raise NotImplementedError, ('Only have expectations for mobile and desktop '
+                                'platforms for v8_browsing tests.')
+
   @classmethod
   def ValueCanBeAddedPredicate(cls, value, is_first_result):
     # TODO(crbug.com/610962): Remove this stopgap when the perf dashboard
diff --git a/tools/perf/page_sets/system_health/background_stories.py b/tools/perf/page_sets/system_health/background_stories.py
index 1d4bc27e..16a823c 100644
--- a/tools/perf/page_sets/system_health/background_stories.py
+++ b/tools/perf/page_sets/system_health/background_stories.py
@@ -7,8 +7,6 @@
 from page_sets.system_health import system_health_story
 from page_sets.system_health.loading_stories import LoadGmailMobileStory
 
-from telemetry import decorators
-
 _WAIT_FOR_VIDEO_SECONDS = 5
 
 class _BackgroundStory(system_health_story.SystemHealthStory):
@@ -83,7 +81,6 @@
   SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY
 
 
-@decorators.Disabled('android')  # crbug.com/676336
 class BackgroundGmailMobileStory(LoadGmailMobileStory):
   NAME = 'background:tools:gmail'
   SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY
diff --git a/tools/perf/page_sets/system_health/browsing_stories.py b/tools/perf/page_sets/system_health/browsing_stories.py
index 0fcc6db..4947859 100644
--- a/tools/perf/page_sets/system_health/browsing_stories.py
+++ b/tools/perf/page_sets/system_health/browsing_stories.py
@@ -10,7 +10,6 @@
 from page_sets.login_helpers import facebook_login
 from page_sets.login_helpers import pinterest_login
 
-from telemetry import decorators
 from telemetry.util import js_template
 
 
@@ -106,7 +105,6 @@
 ##############################################################################
 
 
-@decorators.Disabled('mac')  # crbug.com/728576
 class CnnStory(_ArticleBrowsingStory):
   """The second top website in http://www.alexa.com/topsites/category/News"""
   NAME = 'browse:news:cnn'
@@ -161,8 +159,6 @@
   SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY
 
 
-# crbug.com/657665 for win and mac
-@decorators.Disabled('win', 'mac')
 class HackerNewsDesktopStory(_ArticleBrowsingStory):
   NAME = 'browse:news:hackernews'
   URL = 'https://news.ycombinator.com'
@@ -248,7 +244,6 @@
 ##############################################################################
 
 
-@decorators.Disabled('win')  # crbug.com/673775
 class GoogleDesktopStory(_ArticleBrowsingStory):
   """
   A typical google search story:
@@ -514,7 +509,6 @@
 ##############################################################################
 
 
-@decorators.Disabled('android')  # crbug.com/708300.
 class BrowseFlipKartMobileStory(_ArticleBrowsingStory):
   NAME = 'browse:shopping:flipkart'
   URL = 'https://flipkart.com/search?q=Sunglasses'
@@ -564,7 +558,6 @@
   ITEMS_TO_VISIT = 4
 
 
-@decorators.Disabled('android')  # crbug.com/728081
 class BrowseTOIMobileStory(_ArticleBrowsingStory):
   NAME = 'browse:news:toi'
   URL = 'http://m.timesofindia.com'
@@ -575,7 +568,6 @@
   ITEM_SELECTOR = '.dummy-img'
 
 
-@decorators.Disabled('android')  # crbug.com/714650
 class BrowseGloboMobileStory(_ArticleBrowsingStory):
   NAME = 'browse:news:globo'
   URL = 'http://www.globo.com'
@@ -653,8 +645,6 @@
     action_runner.ClickElement(selector=selector)
 
 
-# crbug.com/712694 on all platforms.
-@decorators.Disabled('all')
 class GoogleMapsStory(_BrowsingStory):
   """
   Google maps story:
@@ -737,8 +727,6 @@
     action_runner.Wait(2)
 
 
-# crbug.com/708590 on all platforms.
-@decorators.Disabled('all')
 class GoogleEarthStory(_BrowsingStory):
   """
   Google Earth story:
@@ -849,7 +837,6 @@
     return 'Load %s then make a very long scroll.' % cls.URL
 
 
-@decorators.Disabled('win', 'linux')  # crbug.com/728152
 class DiscourseDesktopStory(_InfiniteScrollStory):
   NAME = 'browse:tech:discourse_infinite_scroll'
   URL = ('https://meta.discourse.org/t/the-official-discourse-tags-plugin-discourse-tagging/26482')
@@ -865,7 +852,6 @@
   TAGS = [story_tags.INFINITE_SCROLL]
 
 
-@decorators.Disabled('win')  # crbug.com/728152
 class FacebookScrollDesktopStory(_InfiniteScrollStory):
   NAME = 'browse:social:facebook_infinite_scroll'
   URL = 'https://www.facebook.com/shakira'
@@ -873,7 +859,6 @@
   TAGS = [story_tags.INFINITE_SCROLL]
 
 
-@decorators.Disabled('all')  # crbug.com/727835
 class FacebookScrollMobileStory(_InfiniteScrollStory):
   NAME = 'browse:social:facebook_infinite_scroll'
   URL = 'https://m.facebook.com/shakira'
@@ -899,7 +884,6 @@
   TAGS = [story_tags.INFINITE_SCROLL]
 
 
-@decorators.Disabled('android-webview')  # crbug.com/728528
 class PinterestMobileStory(_InfiniteScrollStory):
   NAME = 'browse:social:pinterest_infinite_scroll'
   URL = 'https://www.pinterest.com/all'
@@ -913,7 +897,6 @@
   TAGS = [story_tags.INFINITE_SCROLL]
 
 
-@decorators.Disabled('win')  # crbug.com/728464
 class TwitterScrollDesktopStory(_InfiniteScrollStory):
   NAME = 'browse:social:twitter_infinite_scroll'
   URL = 'https://twitter.com/taylorswift13'
diff --git a/tools/perf/page_sets/system_health/chrome_stories.py b/tools/perf/page_sets/system_health/chrome_stories.py
index 2445ace..20e3014 100644
--- a/tools/perf/page_sets/system_health/chrome_stories.py
+++ b/tools/perf/page_sets/system_health/chrome_stories.py
@@ -6,8 +6,6 @@
 from page_sets.system_health import story_tags
 from page_sets.system_health import system_health_story
 
-from telemetry import decorators
-
 from devil.android.sdk import keyevent # pylint: disable=import-error
 
 
@@ -30,7 +28,6 @@
     action_runner.WaitForJavaScriptCondition("window.__hasRunRAF")
 
 
-@decorators.Disabled('android-webview')  # Webview does not have omnibox
 class SearchOmniboxStory(system_health_story.SystemHealthStory):
   """Story that peforms search by using omnibox search provider
 
@@ -57,7 +54,6 @@
     action_runner.ScrollPage(use_touch=True, distance=500)
 
 
-@decorators.Disabled('android-webview')  # Webview does not have new tab page.
 class MobileNewTabPageStory(system_health_story.SystemHealthStory):
   """Story that loads new tab page and performs searches.
 
diff --git a/tools/perf/page_sets/system_health/expectations.py b/tools/perf/page_sets/system_health/expectations.py
new file mode 100644
index 0000000..567aa7a
--- /dev/null
+++ b/tools/perf/page_sets/system_health/expectations.py
@@ -0,0 +1,179 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+from telemetry.story import expectations
+
+class SystemHealthDesktopCommonExpectations(expectations.StoryExpectations):
+  def SetExpectations(self):
+    self.DisableStory('browse:news:hackernews',
+                      [expectations.ALL_WIN, expectations.ALL_MAC],
+                      'crbug.com/676336')
+    self.DisableStory('browse:search:google', [expectations.ALL_WIN],
+                      'crbug.com/673775')
+    self.DisableStory('browse:tools:maps', [expectations.ALL],
+                      'crbug.com/712694')
+    self.DisableStory('browse:tools:earth', [expectations.ALL],
+                      'crbug.com/708590')
+    self.DisableStory('load:games:miniclip', [expectations.ALL_MAC],
+                      'crbug.com/664661')
+    self.DisableStory('play:media:google_play_music', [expectations.ALL],
+                      'crbug.com/649392')
+    self.DisableStory('play:media:soundcloud', [expectations.ALL_WIN],
+                      'crbug.com/649392')
+    self.DisableStory('play:media:pandora', [expectations.ALL],
+                      'crbug.com/64939')
+    self.DisableStory('browse:tech:discourse_infinite_scroll',
+                      [expectations.ALL_WIN, expectations.ALL_LINUX],
+                      'crbug.com/728152')
+    self.DisableStory('browse:social:facebook_infinite_scroll',
+                      [expectations.ALL_WIN], 'crbug.com/728152')
+    self.DisableStory('browse:news:cnn',
+                      [expectations.ALL_MAC], 'crbug.com/728576')
+    self.DisableStory('browse:social:twitter_infinite_scroll',
+                      [expectations.ALL_WIN], 'crbug.com/728464')
+
+
+class SystemHealthDesktopMemoryExpectations(expectations.StoryExpectations):
+  def SetExpectations(self):
+    self.DisableStory('browse:news:hackernews',
+                      [expectations.ALL_WIN, expectations.ALL_MAC],
+                      'crbug.com/676336')
+    self.DisableStory('browse:search:google', [expectations.ALL_WIN],
+                      'crbug.com/673775')
+    self.DisableStory('browse:tools:maps', [expectations.ALL],
+                      'crbug.com/712694')
+    self.DisableStory('browse:tools:earth', [expectations.ALL],
+                      'crbug.com/708590')
+    self.DisableStory('load:games:miniclip', [expectations.ALL_MAC],
+                      'crbug.com/664661')
+    self.DisableStory('play:media:google_play_music', [expectations.ALL],
+                      'crbug.com/649392')
+    self.DisableStory('play:media:soundcloud', [expectations.ALL_WIN],
+                      'crbug.com/649392')
+    self.DisableStory('play:media:pandora', [expectations.ALL],
+                      'crbug.com/64939')
+    self.DisableStory('browse:tech:discourse_infinite_scroll',
+                      [expectations.ALL_WIN, expectations.ALL_LINUX],
+                      'crbug.com/728152')
+    self.DisableStory('browse:social:facebook_infinite_scroll',
+                      [expectations.ALL_WIN], 'crbug.com/728152')
+    self.DisableStory('browse:news:cnn',
+                      [expectations.ALL_MAC], 'crbug.com/728576')
+    self.DisableStory('browse:social:twitter_infinite_scroll',
+                      [expectations.ALL_WIN], 'crbug.com/728464')
+
+
+class SystemHealthMobileCommonExpectations(expectations.StoryExpectations):
+  def SetExpectations(self):
+    self.DisableStory('background:tools:gmail', [expectations.ALL_ANDROID],
+                      'crbug.com/723783')
+    self.DisableStory('browse:shopping:flipkart', [expectations.ALL_ANDROID],
+                      'crbug.com/708300')
+    self.DisableStory('browse:news:globo', [expectations.ALL_ANDROID],
+                      'crbug.com/714650')
+    self.DisableStory('load:tools:gmail', [expectations.ALL_ANDROID],
+                      'crbug.com/657433')
+    self.DisableStory('long_running:tools:gmail-background',
+                      [expectations.ALL_ANDROID], 'crbug.com/726301')
+    self.DisableStory('long_running:tools:gmail-foreground',
+                      [expectations.ALL_ANDROID], 'crbug.com/726301')
+    self.DisableStory('browse:news:toi', [expectations.ALL_ANDROID],
+                      'crbug.com/728081')
+    self.DisableStory('browse:social:facebook_infinite_scroll',
+                      [expectations.ALL], 'crbug.com/728152')
+    # TODO(rnephew): This disabling should move to CanRunOnBrowser.
+    self.DisableStory('browse:chrome:omnibox',
+                      [expectations.ANDROID_WEBVIEW],
+                      'Webview does not have omnibox')
+    # TODO(rnephew): This disabling should move to CanRunOnBrowser.
+    self.DisableStory('browse:chrome:newtab',
+                      [expectations.ANDROID_WEBVIEW],
+                      'Webview does not have NTP')
+    # TODO(rnephew): This disabling should move to CanRunOnBrowser.
+    self.DisableStory('long_running:tools:gmail-background',
+                      [expectations.ANDROID_WEBVIEW],
+                      'Webview does not have tabs')
+    self.DisableStory('browse:social:pinterest_infinite_scroll',
+                      [expectations.ANDROID_WEBVIEW], 'crbug.com/728528')
+
+
+class SystemHealthMobileMemoryExpectations(expectations.StoryExpectations):
+  def SetExpectations(self):
+    self.DisableStory('background:tools:gmail', [expectations.ALL_ANDROID],
+                      'crbug.com/723783')
+    self.DisableStory('browse:shopping:flipkart', [expectations.ALL_ANDROID],
+                      'crbug.com/708300')
+    self.DisableStory('browse:news:globo', [expectations.ALL_ANDROID],
+                      'crbug.com/714650')
+    self.DisableStory('load:tools:gmail', [expectations.ALL_ANDROID],
+                      'crbug.com/657433')
+    self.DisableStory('long_running:tools:gmail-background',
+                      [expectations.ALL_ANDROID], 'crbug.com/726301')
+    self.DisableStory('long_running:tools:gmail-foreground',
+                      [expectations.ALL_ANDROID], 'crbug.com/726301')
+    self.DisableStory('browse:news:toi', [expectations.ALL_ANDROID],
+                      'crbug.com/728081')
+    self.DisableStory('browse:social:facebook_infinite_scroll',
+                      [expectations.ALL], 'crbug.com/728152')
+    # TODO(rnephew): This disabling should move to CanRunOnBrowser.
+    self.DisableStory('browse:chrome:omnibox',
+                      [expectations.ANDROID_WEBVIEW],
+                      'Webview does not have omnibox')
+    # TODO(rnephew): This disabling should move to CanRunOnBrowser.
+    self.DisableStory('browse:chrome:newtab',
+                      [expectations.ANDROID_WEBVIEW],
+                      'Webview does not have NTP')
+    # TODO(rnephew): This disabling should move to CanRunOnBrowser.
+    self.DisableStory('long_running:tools:gmail-background',
+                      [expectations.ANDROID_WEBVIEW],
+                      'Webview does not have tabs')
+    self.DisableStory('browse:social:pinterest_infinite_scroll',
+                      [expectations.ANDROID_WEBVIEW], 'crbug.com/728528')
+
+
+# Should only include browse:*:* stories.
+class V8BrowsingDesktopExpecations(expectations.StoryExpectations):
+  def SetExpectations(self):
+    self.DisableStory('browse:news:hackernews',
+                      [expectations.ALL_WIN, expectations.ALL_MAC],
+                      'crbug.com/676336')
+    self.DisableStory('browse:search:google', [expectations.ALL_WIN],
+                      'crbug.com/673775')
+    self.DisableStory('browse:tools:maps', [expectations.ALL],
+                      'crbug.com/712694')
+    self.DisableStory('browse:tools:earth', [expectations.ALL],
+                      'crbug.com/708590')
+    self.DisableStory('browse:tech:discourse_infinite_scroll',
+                      [expectations.ALL_WIN, expectations.ALL_LINUX],
+                      'crbug.com/728152')
+    self.DisableStory('browse:news:cnn',
+                      [expectations.ALL_MAC], 'crbug.com/728576')
+    self.DisableStory('browse:social:twitter_infinite_scroll',
+                      [expectations.ALL_WIN], 'crbug.com/728464')
+
+# Should only include browse:*:* stories.
+class V8BrowsingMobileExpecations(expectations.StoryExpectations):
+  def SetExpectations(self):
+    self.DisableStory('browse:shopping:flipkart', [expectations.ALL_ANDROID],
+                      'crbug.com/708300')
+    self.DisableStory('browse:news:globo', [expectations.ALL_ANDROID],
+                      'crbug.com/714650')
+    self.DisableStory('browse:news:toi', [expectations.ALL_ANDROID],
+                      'crbug.com/728081')
+    self.DisableStory('browse:social:facebook_infinite_scroll',
+                      [expectations.ALL], 'crbug.com/728152')
+    # TODO(rnephew): This disabling should move to CanRunOnBrowser.
+    self.DisableStory('browse:chrome:omnibox',
+                      [expectations.ANDROID_WEBVIEW],
+                      'Webview does not have omnibox')
+    # TODO(rnephew): This disabling should move to CanRunOnBrowser.
+    self.DisableStory('browse:chrome:newtab',
+                      [expectations.ANDROID_WEBVIEW],
+                      'Webview does not have NTP')
+    self.DisableStory('browse:social:pinterest_infinite_scroll',
+                      [expectations.ANDROID_WEBVIEW], 'crbug.com/728528')
+
+
+class SystemHealthWebviewStartupExpectations(expectations.StoryExpectations):
+  def SetExpectations(self):
+    pass # Nothing is disabled at this time.
diff --git a/tools/perf/page_sets/system_health/loading_stories.py b/tools/perf/page_sets/system_health/loading_stories.py
index f85a2a3..828af12 100644
--- a/tools/perf/page_sets/system_health/loading_stories.py
+++ b/tools/perf/page_sets/system_health/loading_stories.py
@@ -9,8 +9,6 @@
 from page_sets.login_helpers import dropbox_login
 from page_sets.login_helpers import google_login
 
-from telemetry import decorators
-
 
 class _LoadingStory(system_health_story.SystemHealthStory):
   """Abstract base class for single-page System Health user stories."""
@@ -333,7 +331,6 @@
         'document.getElementById("loading").style.display === "none"')
 
 
-@decorators.Disabled('android')  # crbug.com/657433
 class LoadGmailMobileStory(_LoadGmailBaseStory):
   SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY
 
@@ -409,7 +406,6 @@
         'document.querySelector("#game canvas").style.background !== ""')
 
 
-@decorators.Disabled('mac') # crbug.com/664661
 class LoadMiniclipStory(_LoadingStory):
   NAME = 'load:games:miniclip'
   # Using "https://" causes "404 Not Found" during WPR recording.
diff --git a/tools/perf/page_sets/system_health/long_running_stories.py b/tools/perf/page_sets/system_health/long_running_stories.py
index 47e634b..45d11a4c 100644
--- a/tools/perf/page_sets/system_health/long_running_stories.py
+++ b/tools/perf/page_sets/system_health/long_running_stories.py
@@ -6,8 +6,6 @@
 from page_sets.system_health import platforms
 from page_sets.system_health import system_health_story
 
-from telemetry import decorators
-
 
 IDLE_TIME_IN_SECONDS = 100
 SAMPLING_INTERVAL_IN_SECONDS = 1
@@ -92,7 +90,6 @@
         'document.getElementById("loading").style.display === "none"')
 
 
-@decorators.Disabled('android')  # crbug.com/726301
 class LongRunningGmailMobileForegroundStory(_LongRunningGmailMobileBase):
   NAME = 'long_running:tools:gmail-foreground'
 
@@ -101,8 +98,6 @@
   NAME = 'long_running:tools:gmail-foreground'
 
 
-@decorators.Disabled('android-webview',  # Weview does not have tabs.
-                     'android')  # crbug.com/726301
 class LongRunningGmailMobileBackgroundStory(_LongRunningGmailMobileBase):
   BACKGROUND = True
   NAME = 'long_running:tools:gmail-background'
diff --git a/tools/perf/page_sets/system_health/media_stories.py b/tools/perf/page_sets/system_health/media_stories.py
index 14edfac..5aea63e 100644
--- a/tools/perf/page_sets/system_health/media_stories.py
+++ b/tools/perf/page_sets/system_health/media_stories.py
@@ -8,9 +8,6 @@
 from page_sets.login_helpers import google_login
 from page_sets.login_helpers import pandora_login
 
-from telemetry import benchmark
-from telemetry import decorators
-
 
 class _MediaStory(system_health_story.SystemHealthStory):
   """Abstract base class for media System Health user stories."""
@@ -56,7 +53,6 @@
 ################################################################################
 
 
-@benchmark.Disabled('all')  # crbug.com/649392
 class GooglePlayMusicDesktopStory(_MediaStory):
   """Browse the songs list in music.google.com, then play a song."""
   NAME = 'play:media:google_play_music'
@@ -82,7 +78,6 @@
                                            self.NAVIGATE_SELECTOR)
 
 
-@benchmark.Disabled('win')  # crbug.com/649392
 class SoundCloudDesktopStory(_MediaStory):
   """Load soundcloud.com, search for "Smooth Jazz", then play a song."""
   NAME = 'play:media:soundcloud'
@@ -101,7 +96,6 @@
     action_runner.PressKey('Return')
 
 
-@decorators.Disabled('all')  # crbug.com/649392
 class PandoraDesktopStory(_MediaStory):
   """Load pandora.com, then play a song."""
   NAME = 'play:media:pandora'
diff --git a/tools/perf/page_sets/system_health/system_health_story.py b/tools/perf/page_sets/system_health/system_health_story.py
index 62b6a6c3f..bb31de8 100644
--- a/tools/perf/page_sets/system_health/system_health_story.py
+++ b/tools/perf/page_sets/system_health/system_health_story.py
@@ -22,6 +22,10 @@
   This class adds support for enabling/disabling individual stories on
   individual platforms using the same approaches as for benchmarks:
 
+  **************
+  *** DEPRECATED: Please use story expectations in ./exepctions.py to disable.
+  **************
+
     1. Disabled/Enabled decorator:
 
        @decorators.Disabled('win')
diff --git a/ui/accessibility/ax_enums.idl b/ui/accessibility/ax_enums.idl
index 88751f8..013fb7e 100644
--- a/ui/accessibility/ax_enums.idl
+++ b/ui/accessibility/ax_enums.idl
@@ -229,7 +229,6 @@
     multiline,
     multiselectable,
     offscreen,
-    pressed,
     protected,
     read_only,
     required,
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux.cc b/ui/accessibility/platform/ax_platform_node_auralinux.cc
index 85a6ec0..846a547e 100644
--- a/ui/accessibility/platform/ax_platform_node_auralinux.cc
+++ b/ui/accessibility/platform/ax_platform_node_auralinux.cc
@@ -476,8 +476,6 @@
     atk_state_set_add_state(atk_state_set, ATK_STATE_EXPANDED);
   if (data.HasState(ui::AX_STATE_FOCUSABLE))
     atk_state_set_add_state(atk_state_set, ATK_STATE_FOCUSABLE);
-  if (data.HasState(ui::AX_STATE_PRESSED))
-    atk_state_set_add_state(atk_state_set, ATK_STATE_PRESSED);
   if (data.HasState(ui::AX_STATE_SELECTABLE))
     atk_state_set_add_state(atk_state_set, ATK_STATE_SELECTABLE);
   if (data.HasState(ui::AX_STATE_SELECTED))
@@ -491,7 +489,10 @@
       atk_state_set_add_state(atk_state_set, ATK_STATE_INDETERMINATE);
       break;
     case ui::AX_CHECKED_STATE_TRUE:
-      atk_state_set_add_state(atk_state_set, ATK_STATE_CHECKED);
+      atk_state_set_add_state(atk_state_set,
+                              data.role == ui::AX_ROLE_TOGGLE_BUTTON
+                                  ? ATK_STATE_PRESSED
+                                  : ATK_STATE_CHECKED);
       break;
     default:
       break;
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc
index 603f69a..d74daa6 100644
--- a/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -1447,8 +1447,6 @@
     msaa_state |= STATE_SYSTEM_LINKED;
   if (state & (1 << ui::AX_STATE_OFFSCREEN))
     msaa_state |= STATE_SYSTEM_OFFSCREEN;
-  if (state & (1 << ui::AX_STATE_PRESSED))
-    msaa_state |= STATE_SYSTEM_PRESSED;
   if (state & (1 << ui::AX_STATE_PROTECTED))
     msaa_state |= STATE_SYSTEM_PROTECTED;
   if (state & (1 << ui::AX_STATE_READ_ONLY))
@@ -1465,7 +1463,9 @@
       GetIntAttribute(ui::AX_ATTR_CHECKED_STATE));
   switch (checked_state) {
     case ui::AX_CHECKED_STATE_TRUE:
-      msaa_state |= STATE_SYSTEM_CHECKED;
+      msaa_state |= data.role == ui::AX_ROLE_TOGGLE_BUTTON
+                        ? STATE_SYSTEM_PRESSED
+                        : STATE_SYSTEM_CHECKED;
       break;
     case ui::AX_CHECKED_STATE_MIXED:
       msaa_state |= STATE_SYSTEM_MIXED;
diff --git a/ui/aura/mus/mus_context_factory.cc b/ui/aura/mus/mus_context_factory.cc
index 443f970d..fd6cd92 100644
--- a/ui/aura/mus/mus_context_factory.cc
+++ b/ui/aura/mus/mus_context_factory.cc
@@ -81,8 +81,8 @@
   return raster_thread_helper_.task_graph_runner();
 }
 
-const cc::RendererSettings& MusContextFactory::GetRendererSettings() const {
-  return renderer_settings_;
+const cc::ResourceSettings& MusContextFactory::GetResourceSettings() const {
+  return renderer_settings_.resource_settings;
 }
 
 }  // namespace aura
diff --git a/ui/aura/mus/mus_context_factory.h b/ui/aura/mus/mus_context_factory.h
index a7624f5..20d67f6b 100644
--- a/ui/aura/mus/mus_context_factory.h
+++ b/ui/aura/mus/mus_context_factory.h
@@ -18,6 +18,10 @@
 #include "ui/aura/aura_export.h"
 #include "ui/compositor/compositor.h"
 
+namespace cc {
+class ResourceSettings;
+}
+
 namespace gpu {
 class GpuChannelHost;
 }
@@ -47,7 +51,7 @@
   double GetRefreshRate() const override;
   gpu::GpuMemoryBufferManager* GetGpuMemoryBufferManager() override;
   cc::TaskGraphRunner* GetTaskGraphRunner() override;
-  const cc::RendererSettings& GetRendererSettings() const override;
+  const cc::ResourceSettings& GetResourceSettings() const override;
   void AddObserver(ui::ContextFactoryObserver* observer) override {}
   void RemoveObserver(ui::ContextFactoryObserver* observer) override {}
 
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc
index 30eff8c7..78bc7f55 100644
--- a/ui/compositor/compositor.cc
+++ b/ui/compositor/compositor.cc
@@ -140,10 +140,9 @@
   // doesn't currently support partial raster.
   settings.use_partial_raster = !settings.use_zero_copy;
 
-  settings.buffer_to_texture_target_map =
-      context_factory_->GetRendererSettings().buffer_to_texture_target_map;
   if (command_line->HasSwitch(switches::kUIEnableRGBA4444Textures))
     settings.preferred_tile_format = cc::RGBA_4444;
+  settings.resource_settings = context_factory_->GetResourceSettings();
 
   settings.gpu_memory_policy.bytes_limit_when_visible = 512 * 1024 * 1024;
   settings.gpu_memory_policy.priority_cutoff_when_visible =
@@ -152,9 +151,6 @@
   settings.disallow_non_exact_resource_reuse =
       command_line->HasSwitch(cc::switches::kDisallowNonExactResourceReuse);
 
-  // TODO(staraz): LayerTreeSettings shouldn't have a RendererSettings.
-  settings.renderer_settings = context_factory_->GetRendererSettings();
-
   base::TimeTicks before_create = base::TimeTicks::Now();
 
   animation_host_ = cc::AnimationHost::CreateMainInstance();
diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h
index 74abc71d..a623386 100644
--- a/ui/compositor/compositor.h
+++ b/ui/compositor/compositor.h
@@ -45,7 +45,7 @@
 class LayerTreeDebugState;
 class LayerTreeHost;
 class LocalSurfaceId;
-class RendererSettings;
+class ResourceSettings;
 class SurfaceManager;
 class TaskGraphRunner;
 }
@@ -159,7 +159,7 @@
   virtual cc::TaskGraphRunner* GetTaskGraphRunner() = 0;
 
   // Gets the renderer settings.
-  virtual const cc::RendererSettings& GetRendererSettings() const = 0;
+  virtual const cc::ResourceSettings& GetResourceSettings() const = 0;
 
   virtual void AddObserver(ContextFactoryObserver* observer) = 0;
 
diff --git a/ui/compositor/compositor_util.cc b/ui/compositor/compositor_util.cc
index 886e7aa..63bc273 100644
--- a/ui/compositor/compositor_util.cc
+++ b/ui/compositor/compositor_util.cc
@@ -39,7 +39,7 @@
          format_idx <= static_cast<int>(gfx::BufferFormat::LAST);
          ++format_idx) {
       gfx::BufferFormat format = static_cast<gfx::BufferFormat>(format_idx);
-      renderer_settings
+      renderer_settings.resource_settings
           .buffer_to_texture_target_map[std::make_pair(usage, format)] =
           get_texture_target(format, usage);
     }
diff --git a/ui/compositor/test/fake_context_factory.cc b/ui/compositor/test/fake_context_factory.cc
index cc0cd26..906c1ee 100644
--- a/ui/compositor/test/fake_context_factory.cc
+++ b/ui/compositor/test/fake_context_factory.cc
@@ -32,7 +32,7 @@
          format_idx <= static_cast<int>(gfx::BufferFormat::LAST);
          ++format_idx) {
       gfx::BufferFormat format = static_cast<gfx::BufferFormat>(format_idx);
-      renderer_settings_
+      renderer_settings_.resource_settings
           .buffer_to_texture_target_map[std::make_pair(usage, format)] =
           GL_TEXTURE_2D;
     }
@@ -73,8 +73,8 @@
   return &task_graph_runner_;
 }
 
-const cc::RendererSettings& FakeContextFactory::GetRendererSettings() const {
-  return renderer_settings_;
+const cc::ResourceSettings& FakeContextFactory::GetResourceSettings() const {
+  return renderer_settings_.resource_settings;
 }
 
 }  // namespace ui
diff --git a/ui/compositor/test/fake_context_factory.h b/ui/compositor/test/fake_context_factory.h
index 7db8233..9be39d8 100644
--- a/ui/compositor/test/fake_context_factory.h
+++ b/ui/compositor/test/fake_context_factory.h
@@ -14,6 +14,7 @@
 class CompositorFrame;
 class ContextProvider;
 class FakeCompositorFrameSink;
+class ResourceSettings;
 class TestTaskGraphRunner;
 class TestGpuMemoryBufferManager;
 }
@@ -35,7 +36,7 @@
   double GetRefreshRate() const override;
   gpu::GpuMemoryBufferManager* GetGpuMemoryBufferManager() override;
   cc::TaskGraphRunner* GetTaskGraphRunner() override;
-  const cc::RendererSettings& GetRendererSettings() const override;
+  const cc::ResourceSettings& GetResourceSettings() const override;
   void AddObserver(ui::ContextFactoryObserver* observer) override {}
   void RemoveObserver(ui::ContextFactoryObserver* observer) override {}
 
diff --git a/ui/compositor/test/in_process_context_factory.cc b/ui/compositor/test/in_process_context_factory.cc
index 8d84e41..1c301a12 100644
--- a/ui/compositor/test/in_process_context_factory.cc
+++ b/ui/compositor/test/in_process_context_factory.cc
@@ -156,7 +156,7 @@
          format_idx <= static_cast<int>(gfx::BufferFormat::LAST);
          ++format_idx) {
       gfx::BufferFormat format = static_cast<gfx::BufferFormat>(format_idx);
-      renderer_settings_
+      renderer_settings_.resource_settings
           .buffer_to_texture_target_map[std::make_pair(usage, format)] =
           GL_TEXTURE_2D;
     }
@@ -328,9 +328,9 @@
   per_compositor_data_[compositor]->display->Resize(size);
 }
 
-const cc::RendererSettings& InProcessContextFactory::GetRendererSettings()
+const cc::ResourceSettings& InProcessContextFactory::GetResourceSettings()
     const {
-  return renderer_settings_;
+  return renderer_settings_.resource_settings;
 }
 
 void InProcessContextFactory::AddObserver(ContextFactoryObserver* observer) {
diff --git a/ui/compositor/test/in_process_context_factory.h b/ui/compositor/test/in_process_context_factory.h
index bb41ede54..d2bf234 100644
--- a/ui/compositor/test/in_process_context_factory.h
+++ b/ui/compositor/test/in_process_context_factory.h
@@ -19,6 +19,7 @@
 #include "ui/compositor/compositor.h"
 
 namespace cc {
+class ResourceSettings;
 class SurfaceManager;
 }
 
@@ -74,7 +75,7 @@
                                  base::TimeTicks timebase,
                                  base::TimeDelta interval) override {}
   void SetOutputIsSecure(ui::Compositor* compositor, bool secure) override {}
-  const cc::RendererSettings& GetRendererSettings() const override;
+  const cc::ResourceSettings& GetResourceSettings() const override;
   void AddObserver(ContextFactoryObserver* observer) override;
   void RemoveObserver(ContextFactoryObserver* observer) override;
 
diff --git a/ui/gfx/paint_vector_icon.cc b/ui/gfx/paint_vector_icon.cc
index 49063b6..f611fe8 100644
--- a/ui/gfx/paint_vector_icon.cc
+++ b/ui/gfx/paint_vector_icon.cc
@@ -19,6 +19,7 @@
 #include "third_party/skia/include/core/SkPath.h"
 #include "ui/gfx/animation/tween.h"
 #include "ui/gfx/canvas.h"
+#include "ui/gfx/color_palette.h"
 #include "ui/gfx/image/canvas_image_source.h"
 #include "ui/gfx/scoped_canvas.h"
 #include "ui/gfx/vector_icon_types.h"
@@ -27,6 +28,17 @@
 
 namespace {
 
+struct CompareIconDescription {
+  bool operator()(const IconDescription& a, const IconDescription& b) const {
+    const VectorIcon* a_icon = &a.icon;
+    const VectorIcon* b_icon = &b.icon;
+    const VectorIcon* a_badge = &a.badge_icon;
+    const VectorIcon* b_badge = &b.badge_icon;
+    return std::tie(a_icon, a.dip_size, a.color, a.elapsed_time, a_badge) <
+           std::tie(b_icon, b.dip_size, b.color, b.elapsed_time, b_badge);
+  }
+};
+
 // Helper that simplifies iterating over a sequence of PathElements.
 class PathParser {
  public:
@@ -437,43 +449,36 @@
 
 class VectorIconSource : public CanvasImageSource {
  public:
-  VectorIconSource(const VectorIcon& icon,
-                   int dip_size,
-                   SkColor color,
-                   const VectorIcon& badge_icon)
-      : CanvasImageSource(Size(dip_size, dip_size), false),
-        color_(color),
-        icon_(icon),
-        badge_(badge_icon) {}
+  explicit VectorIconSource(const IconDescription& data)
+      : CanvasImageSource(Size(data.dip_size, data.dip_size), false),
+        data_(data) {}
 
   VectorIconSource(const std::string& definition, int dip_size, SkColor color)
       : CanvasImageSource(Size(dip_size, dip_size), false),
-        color_(color),
-        icon_(kNoneIcon),
-        badge_(kNoneIcon),
+        data_(kNoneIcon, dip_size, color, base::TimeDelta(), kNoneIcon),
         path_(PathFromSource(definition)) {}
 
   ~VectorIconSource() override {}
 
   // CanvasImageSource:
   bool HasRepresentationAtAllScales() const override {
-    return !icon_.is_empty();
+    return !data_.icon.is_empty();
   }
 
   void Draw(Canvas* canvas) override {
     if (path_.empty()) {
-      PaintVectorIcon(canvas, icon_, size_.width(), color_);
-      if (!badge_.is_empty())
-        PaintVectorIcon(canvas, badge_, size_.width(), color_);
+      PaintVectorIcon(canvas, data_.icon, size_.width(), data_.color,
+                      data_.elapsed_time);
+      if (!data_.badge_icon.is_empty())
+        PaintVectorIcon(canvas, data_.badge_icon, size_.width(), data_.color);
     } else {
-      PaintPath(canvas, path_.data(), size_.width(), color_, base::TimeDelta());
+      PaintPath(canvas, path_.data(), size_.width(), data_.color,
+                base::TimeDelta());
     }
   }
 
  private:
-  const SkColor color_;
-  const VectorIcon& icon_;
-  const VectorIcon& badge_;
+  const IconDescription data_;
   const std::vector<PathElement> path_;
 
   DISALLOW_COPY_AND_ASSIGN(VectorIconSource);
@@ -487,46 +492,19 @@
   VectorIconCache() {}
   ~VectorIconCache() {}
 
-  ImageSkia GetOrCreateIcon(const VectorIcon& icon,
-                            int dip_size,
-                            SkColor color,
-                            const VectorIcon& badge_icon) {
-    IconDescription description(&icon, dip_size, color, &badge_icon);
+  ImageSkia GetOrCreateIcon(const IconDescription& description) {
     auto iter = images_.find(description);
     if (iter != images_.end())
       return iter->second;
 
-    ImageSkia icon_image(
-        new VectorIconSource(icon, dip_size, color, badge_icon),
-        Size(dip_size, dip_size));
+    ImageSkia icon_image(new VectorIconSource(description),
+                         Size(description.dip_size, description.dip_size));
     images_.insert(std::make_pair(description, icon_image));
     return icon_image;
   }
 
  private:
-  struct IconDescription {
-    IconDescription(const VectorIcon* icon,
-                    int dip_size,
-                    SkColor color,
-                    const VectorIcon* badge_icon)
-        : icon(icon),
-          dip_size(dip_size),
-          color(color),
-          badge_icon(badge_icon) {}
-
-    bool operator<(const IconDescription& other) const {
-      return std::tie(icon, dip_size, color, badge_icon) <
-             std::tie(other.icon, other.dip_size, other.color,
-                      other.badge_icon);
-    }
-
-    const VectorIcon* icon;
-    int dip_size;
-    SkColor color;
-    const VectorIcon* badge_icon;
-  };
-
-  std::map<IconDescription, ImageSkia> images_;
+  std::map<IconDescription, ImageSkia, CompareIconDescription> images_;
 
   DISALLOW_COPY_AND_ASSIGN(VectorIconCache);
 };
@@ -536,6 +514,24 @@
 
 }  // namespace
 
+IconDescription::IconDescription(const IconDescription& other) = default;
+
+IconDescription::IconDescription(const VectorIcon& icon,
+                                 int dip_size,
+                                 SkColor color,
+                                 const base::TimeDelta& elapsed_time,
+                                 const VectorIcon& badge_icon)
+    : icon(icon),
+      dip_size(dip_size),
+      color(color),
+      elapsed_time(elapsed_time),
+      badge_icon(badge_icon) {
+  if (dip_size == 0)
+    this->dip_size = GetDefaultSizeOfVectorIcon(icon);
+}
+
+IconDescription::~IconDescription() {}
+
 const VectorIcon kNoneIcon = {};
 
 void PaintVectorIcon(Canvas* canvas,
@@ -557,6 +553,13 @@
   PaintPath(canvas, path, dip_size, color, elapsed_time);
 }
 
+ImageSkia CreateVectorIcon(const IconDescription& params) {
+  if (params.icon.is_empty())
+    return gfx::ImageSkia();
+
+  return g_icon_cache.Get().GetOrCreateIcon(params);
+}
+
 ImageSkia CreateVectorIcon(const VectorIcon& icon, SkColor color) {
   return CreateVectorIcon(icon, GetDefaultSizeOfVectorIcon(icon), color);
 }
@@ -564,16 +567,16 @@
 ImageSkia CreateVectorIcon(const VectorIcon& icon,
                            int dip_size,
                            SkColor color) {
-  return CreateVectorIconWithBadge(icon, dip_size, color, kNoneIcon);
+  return CreateVectorIcon(
+      IconDescription(icon, dip_size, color, base::TimeDelta(), kNoneIcon));
 }
 
 ImageSkia CreateVectorIconWithBadge(const VectorIcon& icon,
                                     int dip_size,
                                     SkColor color,
                                     const VectorIcon& badge_icon) {
-  return icon.is_empty() ? ImageSkia()
-                         : g_icon_cache.Get().GetOrCreateIcon(
-                               icon, dip_size, color, badge_icon);
+  return CreateVectorIcon(
+      IconDescription(icon, dip_size, color, base::TimeDelta(), badge_icon));
 }
 
 ImageSkia CreateVectorIconFromSource(const std::string& source,
diff --git a/ui/gfx/paint_vector_icon.h b/ui/gfx/paint_vector_icon.h
index 2200043..b953dce1 100644
--- a/ui/gfx/paint_vector_icon.h
+++ b/ui/gfx/paint_vector_icon.h
@@ -15,6 +15,26 @@
 class Canvas;
 struct VectorIcon;
 
+// Describes an instance of an icon: an icon definition and a set of drawing
+// parameters.
+struct GFX_EXPORT IconDescription {
+  IconDescription(const IconDescription& other);
+
+  IconDescription(const VectorIcon& icon,
+                  int dip_size,
+                  SkColor color,
+                  const base::TimeDelta& elapsed_time,
+                  const VectorIcon& badge_icon);
+
+  ~IconDescription();
+
+  const VectorIcon& icon;
+  int dip_size;
+  SkColor color;
+  const base::TimeDelta elapsed_time;
+  const VectorIcon& badge_icon;
+};
+
 GFX_EXPORT extern const VectorIcon kNoneIcon;
 
 // Draws a vector icon identified by |id| onto |canvas| at (0, 0). |color| is
@@ -36,6 +56,11 @@
     SkColor color,
     const base::TimeDelta& elapsed_time = base::TimeDelta());
 
+// Creates an ImageSkia which will render the icon on demand.
+// TODO(estade): update clients to use this version and remove the other
+// CreateVectorIcon()s.
+GFX_EXPORT ImageSkia CreateVectorIcon(const IconDescription& params);
+
 // Creates an ImageSkia which will render the icon on demand. The size will come
 // from the .icon file (the 1x version, if multiple versions exist).
 GFX_EXPORT ImageSkia CreateVectorIcon(const VectorIcon& icon, SkColor color);
@@ -66,7 +91,7 @@
 
 // Calculates and returns the elapsed time at which all animations/transitions
 // will be finished.
-base::TimeDelta GetDurationOfAnimation(const VectorIcon& icon);
+GFX_EXPORT base::TimeDelta GetDurationOfAnimation(const VectorIcon& icon);
 
 }  // namespace gfx
 
diff --git a/ui/ozone/platform/drm/host/drm_display_host_manager.cc b/ui/ozone/platform/drm/host/drm_display_host_manager.cc
index eefd7e9..8411915d 100644
--- a/ui/ozone/platform/drm/host/drm_display_host_manager.cc
+++ b/ui/ozone/platform/drm/host/drm_display_host_manager.cc
@@ -24,6 +24,7 @@
 #include "ui/ozone/platform/drm/host/drm_device_handle.h"
 #include "ui/ozone/platform/drm/host/drm_display_host.h"
 #include "ui/ozone/platform/drm/host/drm_native_display_delegate.h"
+#include "ui/ozone/platform/drm/host/drm_overlay_manager.h"
 #include "ui/ozone/platform/drm/host/gpu_thread_adapter.h"
 
 namespace ui {
@@ -110,9 +111,11 @@
 DrmDisplayHostManager::DrmDisplayHostManager(
     GpuThreadAdapter* proxy,
     DeviceManager* device_manager,
+    DrmOverlayManager* overlay_manager,
     InputControllerEvdev* input_controller)
     : proxy_(proxy),
       device_manager_(device_manager),
+      overlay_manager_(overlay_manager),
       input_controller_(input_controller),
       primary_graphics_card_path_(GetPrimaryDisplayCardPath()),
       weak_ptr_factory_(this) {
@@ -391,10 +394,12 @@
 void DrmDisplayHostManager::GpuConfiguredDisplay(int64_t display_id,
                                                  bool status) {
   DrmDisplayHost* display = GetDisplay(display_id);
-  if (display)
+  if (display) {
     display->OnDisplayConfigured(status);
-  else
+    overlay_manager_->ResetCache();
+  } else {
     LOG(ERROR) << "Couldn't find display with id=" << display_id;
+  }
 }
 
 void DrmDisplayHostManager::GpuReceivedHDCPState(int64_t display_id,
diff --git a/ui/ozone/platform/drm/host/drm_display_host_manager.h b/ui/ozone/platform/drm/host/drm_display_host_manager.h
index 48097c7..23cd830f 100644
--- a/ui/ozone/platform/drm/host/drm_display_host_manager.h
+++ b/ui/ozone/platform/drm/host/drm_display_host_manager.h
@@ -28,6 +28,7 @@
 class DrmDisplayHost;
 class DrmDisplayHostManager;
 class DrmNativeDisplayDelegate;
+class DrmOverlayManager;
 class GpuThreadAdapter;
 
 struct DisplaySnapshot_Params;
@@ -39,6 +40,7 @@
  public:
   DrmDisplayHostManager(GpuThreadAdapter* proxy,
                         DeviceManager* device_manager,
+                        DrmOverlayManager* overlay_manager,
                         InputControllerEvdev* input_controller);
   ~DrmDisplayHostManager() override;
 
@@ -100,6 +102,7 @@
 
   GpuThreadAdapter* proxy_;                 // Not owned.
   DeviceManager* device_manager_;           // Not owned.
+  DrmOverlayManager* overlay_manager_;      // Not owned.
   InputControllerEvdev* input_controller_;  // Not owned.
 
   DrmNativeDisplayDelegate* delegate_ = nullptr;  // Not owned.
diff --git a/ui/ozone/platform/drm/ozone_platform_gbm.cc b/ui/ozone/platform/drm/ozone_platform_gbm.cc
index df0cb0a2..1ae295d 100644
--- a/ui/ozone/platform/drm/ozone_platform_gbm.cc
+++ b/ui/ozone/platform/drm/ozone_platform_gbm.cc
@@ -191,12 +191,12 @@
       adapter = gpu_platform_support_host_.get();
     }
 
-    display_manager_.reset(
-        new DrmDisplayHostManager(adapter, device_manager_.get(),
-                                  event_factory_ozone_->input_controller()));
-    cursor_factory_ozone_.reset(new BitmapCursorFactoryOzone);
     overlay_manager_.reset(
         new DrmOverlayManager(adapter, window_manager_.get()));
+    display_manager_.reset(new DrmDisplayHostManager(
+        adapter, device_manager_.get(), overlay_manager_.get(),
+        event_factory_ozone_->input_controller()));
+    cursor_factory_ozone_.reset(new BitmapCursorFactoryOzone);
 
     if (using_mojo_ || single_process_) {
       mus_thread_proxy_->ProvideManagers(display_manager_.get(),
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn
index 4a2cb6a1..5a59c2e 100644
--- a/ui/views/BUILD.gn
+++ b/ui/views/BUILD.gn
@@ -112,6 +112,8 @@
     "color_chooser/color_chooser_view.cc",
     "color_chooser/color_chooser_view.h",
     "context_menu_controller.h",
+    "controls/animated_icon_view.cc",
+    "controls/animated_icon_view.h",
     "controls/button/blue_button.cc",
     "controls/button/blue_button.h",
     "controls/button/button.cc",
diff --git a/ui/views/controls/animated_icon_view.cc b/ui/views/controls/animated_icon_view.cc
new file mode 100644
index 0000000..055b327d
--- /dev/null
+++ b/ui/views/controls/animated_icon_view.cc
@@ -0,0 +1,74 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/controls/animated_icon_view.h"
+
+#include "ui/compositor/compositor.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/color_palette.h"
+#include "ui/gfx/paint_vector_icon.h"
+#include "ui/views/widget/widget.h"
+
+namespace views {
+
+AnimatedIconView::AnimatedIconView(const gfx::VectorIcon& icon)
+    : icon_(icon),
+      color_(gfx::kPlaceholderColor),
+      duration_(gfx::GetDurationOfAnimation(icon)) {
+  UpdateStaticImage();
+}
+
+AnimatedIconView::~AnimatedIconView() {}
+
+void AnimatedIconView::Animate(State target) {
+  SetState(target);
+  if (!IsAnimating())
+    GetWidget()->GetCompositor()->AddAnimationObserver(this);
+  start_time_ = base::TimeTicks::Now();
+}
+
+void AnimatedIconView::SetState(State state) {
+  state_ = state;
+  UpdateStaticImage();
+}
+
+void AnimatedIconView::OnPaint(gfx::Canvas* canvas) {
+  if (!IsAnimating()) {
+    views::ImageView::OnPaint(canvas);
+    return;
+  }
+
+  auto timestamp = base::TimeTicks::Now();
+  base::TimeDelta elapsed = timestamp - start_time_;
+  if (state_ == END)
+    elapsed = start_time_ + duration_ - timestamp;
+
+  canvas->Translate(GetImageBounds().OffsetFromOrigin());
+  gfx::PaintVectorIcon(canvas, icon_, color_, elapsed);
+}
+
+void AnimatedIconView::OnAnimationStep(base::TimeTicks timestamp) {
+  base::TimeDelta elapsed = timestamp - start_time_;
+  if (elapsed > duration_) {
+    GetWidget()->GetCompositor()->RemoveAnimationObserver(this);
+    start_time_ = base::TimeTicks();
+  }
+
+  SchedulePaint();
+}
+
+void AnimatedIconView::OnCompositingShuttingDown(ui::Compositor* compositor) {}
+
+bool AnimatedIconView::IsAnimating() const {
+  return start_time_ != base::TimeTicks();
+}
+
+void AnimatedIconView::UpdateStaticImage() {
+  gfx::IconDescription description(
+      icon_, 0, color_, state_ == START ? base::TimeDelta() : duration_,
+      gfx::kNoneIcon);
+  SetImage(gfx::CreateVectorIcon(description));
+}
+
+}  // namespace views
diff --git a/ui/views/controls/animated_icon_view.h b/ui/views/controls/animated_icon_view.h
new file mode 100644
index 0000000..eb493eacc
--- /dev/null
+++ b/ui/views/controls/animated_icon_view.h
@@ -0,0 +1,67 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_CONTROLS_ANIMATED_ICON_VIEW_H_
+#define UI_VIEWS_CONTROLS_ANIMATED_ICON_VIEW_H_
+
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "ui/compositor/compositor_animation_observer.h"
+#include "ui/gfx/vector_icon_types.h"
+#include "ui/views/controls/image_view.h"
+
+namespace views {
+
+// This class hosts a vector icon that defines transitions. It can be in the
+// start steady state, the end steady state, or transitioning in between.
+class VIEWS_EXPORT AnimatedIconView : public views::ImageView,
+                                      public ui::CompositorAnimationObserver {
+ public:
+  enum State {
+    START,
+    END,
+  };
+
+  explicit AnimatedIconView(const gfx::VectorIcon& icon);
+  ~AnimatedIconView() override;
+
+  void set_color(SkColor color) { color_ = color; }
+
+  // Animates to the end or start state.
+  void Animate(State target);
+
+  // Jumps to the end or start state.
+  void SetState(State state);
+
+  // views::ImageView
+  void OnPaint(gfx::Canvas* canvas) override;
+
+  // ui::CompositorAnimationObserver
+  void OnAnimationStep(base::TimeTicks timestamp) override;
+  void OnCompositingShuttingDown(ui::Compositor* compositor) override;
+
+ private:
+  bool IsAnimating() const;
+
+  void UpdateStaticImage();
+
+  const gfx::VectorIcon& icon_;
+  SkColor color_;
+
+  // Tracks the last time Animate() was called.
+  base::TimeTicks start_time_;
+
+  // The amount of time that must elapse until all transitions are done, i.e.
+  // the length of the animation.
+  const base::TimeDelta duration_;
+
+  // The current state, or when transitioning the goal state.
+  State state_ = START;
+
+  DISALLOW_COPY_AND_ASSIGN(AnimatedIconView);
+};
+
+}  // namespace views
+
+#endif  // UI_VIEWS_CONTROLS_ANIMATED_ICON_VIEW_H_
diff --git a/ui/views/controls/button/custom_button.cc b/ui/views/controls/button/custom_button.cc
index 2c69362..4ed90e2 100644
--- a/ui/views/controls/button/custom_button.cc
+++ b/ui/views/controls/button/custom_button.cc
@@ -370,7 +370,8 @@
       node_data->AddState(ui::AX_STATE_HOVERED);
       break;
     case STATE_PRESSED:
-      node_data->AddState(ui::AX_STATE_PRESSED);
+      node_data->AddIntAttribute(ui::AX_ATTR_CHECKED_STATE,
+                                 ui::AX_CHECKED_STATE_TRUE);
       break;
     case STATE_DISABLED:
       node_data->AddState(ui::AX_STATE_DISABLED);
diff --git a/ui/views/controls/button/image_button.cc b/ui/views/controls/button/image_button.cc
index 19577bb..364489c 100644
--- a/ui/views/controls/button/image_button.cc
+++ b/ui/views/controls/button/image_button.cc
@@ -267,8 +267,9 @@
   if ((toggled_ && !images_[ButtonState::STATE_NORMAL].isNull()) ||
       (!toggled_ && !alternate_images_[ButtonState::STATE_NORMAL].isNull())) {
     node_data->role = ui::AX_ROLE_TOGGLE_BUTTON;
-    if (toggled_)
-      node_data->AddState(ui::AX_STATE_PRESSED);
+    node_data->AddIntAttribute(
+        ui::AX_ATTR_CHECKED_STATE,
+        toggled_ ? ui::AX_CHECKED_STATE_TRUE : ui::AX_CHECKED_STATE_FALSE);
   }
 }