diff --git a/DEPS b/DEPS
index 25040a008..13e40394 100644
--- a/DEPS
+++ b/DEPS
@@ -39,11 +39,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '4eeccc9de7d2381df85d68e0331a40cddf5989b1',
+  'skia_revision': '85def2e0673f3b75c4500440b95ab3dac7435702',
   # 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': '9c51453ce0a6f1d93b45c2557c7011c8968a4176',
+  'v8_revision': 'b914d669ee4ce4a3056bfe3437b28728cfada6db',
   # 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.
@@ -192,7 +192,7 @@
    Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + '01464a5194f066a2ea2016b02ca3ea2aad4e6376',
 
   'src/third_party/libjingle/source/talk':
-    Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + 'a2ec0b628cdf9ea6f40b19101d765781382437b8', # commit position 12501
+    Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + 'a3dc305df4e8b44cda3569eb77238b2f8cc0ba20', # commit position 12534
 
   'src/third_party/usrsctp/usrsctplib':
     Var('chromium_git') + '/external/github.com/sctplab/usrsctp' + '@' + 'c60ec8b35c3fe6027d7a3faae89d1c8d7dd3ce98',
@@ -216,7 +216,7 @@
    Var('chromium_git') + '/native_client/src/third_party/scons-2.0.1.git' + '@' + '1c1550e17fc26355d08627fbdec13d8291227067',
 
   'src/third_party/webrtc':
-    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + 'de1eeeb3e322944d429cc0c44c4b736dfb9a18e8', # commit position 12519
+    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '57f37afa99e3897f88029ae0edd3c89ddcb73e8e', # commit position 12543
 
   'src/third_party/openmax_dl':
     Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' +  Var('openmax_dl_revision'),
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 949e03ae..874734e 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -1054,6 +1054,9 @@
     if input_api.tbr:
       return [output_api.PresubmitNotifyResult(
           '--tbr was specified, skipping OWNERS check for DEPS additions')]
+    if input_api.dry_run:
+      return [output_api.PresubmitNotifyResult(
+          'This is a dry run, skipping OWNERS check for DEPS additions')]
     if not input_api.change.issue:
       return [output_api.PresubmitError(
           "DEPS approval by OWNERS check failed: this change has "
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 791c29df..4269b3a 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
@@ -86,7 +86,6 @@
     private WebStorageAdapter mWebStorage;
     private WebViewDatabaseAdapter mWebViewDatabase;
     private AwDevToolsServer mDevToolsServer;
-    private Context mWrappedAppContext;
 
     private ArrayList<WeakReference<WebViewChromium>> mWebViewsToStart =
             new ArrayList<WeakReference<WebViewChromium>>();
@@ -115,6 +114,11 @@
     @SuppressFBWarnings("DMI_HARDCODED_ABSOLUTE_FILENAME")
     private void initialize(WebViewDelegate webViewDelegate) {
         mWebViewDelegate = webViewDelegate;
+
+        // WebView needs to make sure to always use the wrapped application context.
+        ContextUtils.initApplicationContext(
+                ResourcesContextWrapperFactory.get(mWebViewDelegate.getApplication()));
+
         if (isBuildDebuggable()) {
             // Suppress the StrictMode violation as this codepath is only hit on debugglable builds.
             StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
@@ -126,7 +130,7 @@
 
         ThreadUtils.setWillOverrideUiThread();
         // Load chromium library.
-        AwBrowserProcess.loadLibrary(getWrappedCurrentApplicationContext());
+        AwBrowserProcess.loadLibrary(ContextUtils.getApplicationContext());
 
         final PackageInfo packageInfo = WebViewFactory.getLoadedPackageInfo();
 
@@ -263,7 +267,7 @@
             return;
         }
 
-        Context context = getWrappedCurrentApplicationContext();
+        Context context = ContextUtils.getApplicationContext();
         try {
             LibraryLoader.get(LibraryProcessType.PROCESS_WEBVIEW).ensureInitialized(context);
         } catch (ProcessInitException e) {
@@ -321,14 +325,6 @@
         }
     }
 
-    private Context getWrappedCurrentApplicationContext() {
-        if (mWrappedAppContext == null) {
-            mWrappedAppContext = ResourcesContextWrapperFactory.get(
-                    mWebViewDelegate.getApplication());
-        }
-        return mWrappedAppContext;
-    }
-
     AwBrowserContext getBrowserContext() {
         synchronized (mLock) {
             return getBrowserContextLocked();
@@ -340,7 +336,7 @@
         assert mStarted;
         if (mBrowserContext == null) {
             mBrowserContext =
-                    new AwBrowserContext(mWebViewPrefs, getWrappedCurrentApplicationContext());
+                    new AwBrowserContext(mWebViewPrefs, ContextUtils.getApplicationContext());
         }
         return mBrowserContext;
     }
@@ -450,13 +446,6 @@
     public CookieManager getCookieManager() {
         synchronized (mLock) {
             if (mCookieManager == null) {
-                if (!mStarted) {
-                    // We can use CookieManager without starting Chromium; the native code
-                    // will bring up just the parts it needs to make this work on a temporary
-                    // basis until Chromium is started for real. The temporary cookie manager
-                    // needs the application context to have been set.
-                    ContextUtils.initApplicationContext(getWrappedCurrentApplicationContext());
-                }
                 mCookieManager = new CookieManagerAdapter(new AwCookieManager());
             }
         }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java
index 993e988..61d9dd9 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java
@@ -4,14 +4,14 @@
 
 package org.chromium.android_webview.test;
 
+import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout;
+
 import android.app.Instrumentation;
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.os.Build;
 import android.util.Log;
 
-import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout;
-
 import org.chromium.android_webview.AwBrowserContext;
 import org.chromium.android_webview.AwBrowserProcess;
 import org.chromium.android_webview.AwContents;
@@ -20,6 +20,7 @@
 import org.chromium.android_webview.AwSwitches;
 import org.chromium.android_webview.test.util.GraphicsTestUtils;
 import org.chromium.android_webview.test.util.JSUtils;
+import org.chromium.base.ContextUtils;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.BaseActivityInstrumentationTestCase;
 import org.chromium.base.test.util.CommandLineFlags;
@@ -79,10 +80,11 @@
 
     @Override
     protected void setUp() throws Exception {
-        mBrowserContext = new AwBrowserContext(
-                new InMemorySharedPreferences(), getInstrumentation().getTargetContext());
+        Context appContext = getInstrumentation().getTargetContext().getApplicationContext();
+        mBrowserContext = new AwBrowserContext(new InMemorySharedPreferences(), appContext);
 
         super.setUp();
+        ContextUtils.initApplicationContext(appContext);
         if (needsBrowserProcessStarted()) {
             startBrowserProcess();
         }
@@ -98,8 +100,10 @@
         });
     }
 
-    /* Override this to return false if the test doesn't want the browser startup sequence to
+    /**
+     * Override this to return false if the test doesn't want the browser startup sequence to
      * be run automatically.
+     * @return Whether the instrumentation test requires the browser process to already be started.
      */
     protected boolean needsBrowserProcessStarted() {
         return true;
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/CookieManagerStartupTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/CookieManagerStartupTest.java
index 6505102..9cb017f 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/CookieManagerStartupTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/CookieManagerStartupTest.java
@@ -14,7 +14,6 @@
 import org.chromium.android_webview.AwWebResourceResponse;
 import org.chromium.android_webview.test.util.CommonResources;
 import org.chromium.android_webview.test.util.CookieUtils;
-import org.chromium.base.ContextUtils;
 import org.chromium.base.test.util.Feature;
 import org.chromium.net.test.util.TestWebServer;
 
@@ -30,7 +29,10 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        ContextUtils.initApplicationContext(getActivity().getApplicationContext());
+        // CookeManager assumes that native is loaded, but webview browser should not be loaded for
+        // these tests as webview is not necessarily loaded when CookieManager is called.
+        AwBrowserProcess.loadLibrary(
+                getInstrumentation().getTargetContext().getApplicationContext());
     }
 
     @Override
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/HttpCacheTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/HttpCacheTest.java
index ebde6683..55083d0 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/HttpCacheTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/HttpCacheTest.java
@@ -10,6 +10,7 @@
 import org.chromium.android_webview.AwBrowserProcess;
 import org.chromium.android_webview.AwContents;
 import org.chromium.android_webview.AwContentsStatics;
+import org.chromium.base.ContextUtils;
 import org.chromium.base.PathUtils;
 import org.chromium.base.test.util.Feature;
 import org.chromium.net.test.util.TestWebServer;
@@ -82,6 +83,7 @@
         assertTrue(dummyCacheFile.exists());
 
         // Set up JNI bindings.
+        ContextUtils.initApplicationContext(targetContext.getApplicationContext());
         AwBrowserProcess.loadLibrary(targetContext);
         // No delay before removing the legacy cache files.
         AwContentsStatics.setLegacyCacheRemovalDelayForTest(0);
diff --git a/android_webview/test/shell/src/org/chromium/android_webview/test/AwTestRunnerActivity.java b/android_webview/test/shell/src/org/chromium/android_webview/test/AwTestRunnerActivity.java
index d87b6302..c3d4ccb 100644
--- a/android_webview/test/shell/src/org/chromium/android_webview/test/AwTestRunnerActivity.java
+++ b/android_webview/test/shell/src/org/chromium/android_webview/test/AwTestRunnerActivity.java
@@ -13,6 +13,7 @@
 
 import org.chromium.android_webview.AwBrowserProcess;
 import org.chromium.android_webview.shell.AwShellResourceProvider;
+import org.chromium.base.ContextUtils;
 
 /**
  * This is a lightweight activity for tests that only require WebView functionality.
@@ -28,6 +29,7 @@
         super.onCreate(savedInstanceState);
 
         AwShellResourceProvider.registerResources(this);
+        ContextUtils.initApplicationContext(getApplicationContext());
         AwBrowserProcess.loadLibrary(this);
 
         mLinearLayout = new LinearLayout(this);
diff --git a/base/android/context_utils.cc b/base/android/context_utils.cc
index fd62c45f..e9ab723 100644
--- a/base/android/context_utils.cc
+++ b/base/android/context_utils.cc
@@ -38,11 +38,6 @@
   return g_application_context.Get().obj();
 }
 
-void InitApplicationContext(JNIEnv* env, const JavaRef<jobject>& context) {
-  SetNativeApplicationContext(env, context);
-  Java_ContextUtils_initJavaSideApplicationContext(env, context.obj());
-}
-
 static void InitNativeSideApplicationContext(
     JNIEnv* env,
     const JavaParamRef<jclass>& clazz,
diff --git a/base/android/context_utils.h b/base/android/context_utils.h
index 52895a9..f172d93 100644
--- a/base/android/context_utils.h
+++ b/base/android/context_utils.h
@@ -18,14 +18,6 @@
 // must NOT release it.
 BASE_EXPORT jobject GetApplicationContext();
 
-// Initialize the global application context object.
-// Either this or the Java equivalent ContextUtils.initApplicationContext must
-// be called once during startup. JNI bindings must have been initialized, as
-// the context is stored on both sides.
-BASE_EXPORT void InitApplicationContext(
-    JNIEnv* env,
-    const base::android::JavaRef<jobject>& context);
-
 bool RegisterContextUtils(JNIEnv* env);
 
 }  // namespace android
diff --git a/base/android/java/src/org/chromium/base/ContextUtils.java b/base/android/java/src/org/chromium/base/ContextUtils.java
index 51adcff..95cdc40 100644
--- a/base/android/java/src/org/chromium/base/ContextUtils.java
+++ b/base/android/java/src/org/chromium/base/ContextUtils.java
@@ -6,7 +6,6 @@
 
 import android.content.Context;
 
-import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 
 /**
@@ -14,6 +13,7 @@
  */
 @JNINamespace("base::android")
 public class ContextUtils {
+    private static final String TAG = "ContextUtils";
     private static Context sApplicationContext;
 
     /**
@@ -29,34 +29,52 @@
      * may make is that it is a Context whose lifetime is the same as the lifetime of the process.
      */
     public static Context getApplicationContext() {
-        assert sApplicationContext != null;
         return sApplicationContext;
     }
 
     /**
-     * Initialize the Android application context.
+     * Initializes the java application context.
      *
-     * Either this or the native equivalent base::android::InitApplicationContext must be called
-     * once during startup. JNI bindings must have been initialized, as the context is stored on
-     * both sides.
+     * This should be called exactly once early on during startup, before native is loaded and
+     * before any other clients make use of the application context through this class.
+     *
+     * @param appContext The application context.
      */
     public static void initApplicationContext(Context appContext) {
-        assert appContext != null;
-        assert sApplicationContext == null || sApplicationContext == appContext;
+        // Conceding that occasionally in tests, native is loaded before the browser process is
+        // started, in which case the browser process re-sets the application context.
+        if (sApplicationContext != null && sApplicationContext != appContext) {
+            throw new RuntimeException("Attempting to set multiple global application contexts.");
+        }
         initJavaSideApplicationContext(appContext);
-        nativeInitNativeSideApplicationContext(appContext);
     }
 
     /**
-     * JUnit Robolectric tests run without native code; allow them to set just the Java-side
-     * context. Do not use in configurations that actually run on Android!
+     * Initialize the native Android application context to be the same as the java counter-part.
      */
-    public static void initApplicationContextForJUnitTests(Context appContext) {
+    public static void initApplicationContextForNative() {
+        if (sApplicationContext == null) {
+            throw new RuntimeException("Cannot have native global application context be null.");
+        }
+        nativeInitNativeSideApplicationContext(sApplicationContext);
+    }
+
+    /**
+     * Occasionally tests cannot ensure the application context doesn't change between tests (junit)
+     * and sometimes specific tests has its own special needs, initApplicationContext should be used
+     * as much as possible, but this method can be used to override it.
+     *
+     * @param appContext The new application context.
+     */
+    @VisibleForTesting
+    public static void initApplicationContextForTests(Context appContext) {
         initJavaSideApplicationContext(appContext);
     }
 
-    @CalledByNative
     private static void initJavaSideApplicationContext(Context appContext) {
+        if (appContext == null) {
+            throw new RuntimeException("Global application context cannot be set to null.");
+        }
         sApplicationContext = appContext;
     }
 
diff --git a/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java b/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java
index 6665ddfd..7858271 100644
--- a/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java
+++ b/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java
@@ -13,6 +13,7 @@
 import android.os.SystemClock;
 
 import org.chromium.base.CommandLine;
+import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
 import org.chromium.base.PackageUtils;
 import org.chromium.base.TraceEvent;
@@ -132,6 +133,8 @@
      *  @param context The context in which the method is called.
      */
     public void ensureInitialized(Context context) throws ProcessInitException {
+        // TODO(wnwen): Move this call appropriately down to the tests that need it.
+        ContextUtils.initApplicationContext(context.getApplicationContext());
         synchronized (sLock) {
             if (mInitialized) {
                 // Already initialized, nothing to do.
@@ -360,6 +363,10 @@
         nativeInitCommandLine(CommandLine.getJavaSwitchesOrNull());
         CommandLine.enableNativeProxy();
         mCommandLineSwitched = true;
+
+        // Ensure that native side application context is loaded and in sync with java side. Must do
+        // this here so webview also gets its application context set before fully initializing.
+        ContextUtils.initApplicationContextForNative();
     }
 
     // Invoke base::android::LibraryLoaded in library_loader_hooks.cc
@@ -368,23 +375,13 @@
             return;
         }
 
-        // Setup the native command line if necessary.
-        if (!mCommandLineSwitched) {
-            nativeInitCommandLine(CommandLine.getJavaSwitchesOrNull());
-        }
+        ensureCommandLineSwitchedAlreadyLocked();
 
         if (!nativeLibraryLoaded()) {
             Log.e(TAG, "error calling nativeLibraryLoaded");
             throw new ProcessInitException(LoaderErrors.LOADER_ERROR_FAILED_TO_REGISTER_JNI);
         }
 
-        // The Chrome JNI is registered by now so we can switch the Java
-        // command line over to delegating to native if it's necessary.
-        if (!mCommandLineSwitched) {
-            CommandLine.enableNativeProxy();
-            mCommandLineSwitched = true;
-        }
-
         // From now on, keep tracing in sync with native.
         TraceEvent.registerNativeEnabledObserver();
 
diff --git a/base/task_scheduler/delayed_task_manager.cc b/base/task_scheduler/delayed_task_manager.cc
index 0b8c2f9..6286d5e 100644
--- a/base/task_scheduler/delayed_task_manager.cc
+++ b/base/task_scheduler/delayed_task_manager.cc
@@ -15,10 +15,12 @@
 struct DelayedTaskManager::DelayedTask {
   DelayedTask(std::unique_ptr<Task> task,
               scoped_refptr<Sequence> sequence,
+              SchedulerWorkerThread* worker_thread,
               SchedulerThreadPool* thread_pool,
               uint64_t index)
       : task(std::move(task)),
         sequence(std::move(sequence)),
+        worker_thread(worker_thread),
         thread_pool(thread_pool),
         index(index) {}
 
@@ -28,10 +30,11 @@
 
   DelayedTask& operator=(DelayedTask&& other) = default;
 
-  // |task| will be posted to |thread_pool| as part of |sequence| when it
-  // becomes ripe for execution.
+  // |task| will be posted to |thread_pool| with |sequence| and |worker_thread|
+  // when it becomes ripe for execution.
   std::unique_ptr<Task> task;
   scoped_refptr<Sequence> sequence;
+  SchedulerWorkerThread* worker_thread;
   SchedulerThreadPool* thread_pool;
 
   // Ensures that tasks that have the same |delayed_run_time| are sorted
@@ -52,6 +55,7 @@
 
 void DelayedTaskManager::AddDelayedTask(std::unique_ptr<Task> task,
                                         scoped_refptr<Sequence> sequence,
+                                        SchedulerWorkerThread* worker_thread,
                                         SchedulerThreadPool* thread_pool) {
   DCHECK(task);
   DCHECK(sequence);
@@ -66,8 +70,8 @@
     if (!delayed_tasks_.empty())
       current_delayed_run_time = delayed_tasks_.top().task->delayed_run_time;
 
-    delayed_tasks_.emplace(std::move(task), std::move(sequence), thread_pool,
-                           ++delayed_task_index_);
+    delayed_tasks_.emplace(std::move(task), std::move(sequence), worker_thread,
+                           thread_pool, ++delayed_task_index_);
   }
 
   if (current_delayed_run_time.is_null() ||
@@ -100,7 +104,8 @@
   // Post delayed tasks that are ready for execution.
   for (auto& delayed_task : ready_tasks) {
     delayed_task.thread_pool->PostTaskWithSequenceNow(
-        std::move(delayed_task.task), std::move(delayed_task.sequence));
+        std::move(delayed_task.task), std::move(delayed_task.sequence),
+        delayed_task.worker_thread);
   }
 }
 
diff --git a/base/task_scheduler/delayed_task_manager.h b/base/task_scheduler/delayed_task_manager.h
index 9113fc5..0637026 100644
--- a/base/task_scheduler/delayed_task_manager.h
+++ b/base/task_scheduler/delayed_task_manager.h
@@ -24,10 +24,10 @@
 namespace internal {
 
 class SchedulerThreadPool;
+class SchedulerWorkerThread;
 
 // A DelayedTaskManager holds delayed Tasks until they become ripe for
-// execution. When they become ripe for execution, it posts them to their
-// associated Sequence and SchedulerThreadPool. This class is thread-safe.
+// execution. This class is thread-safe.
 class BASE_EXPORT DelayedTaskManager {
  public:
   // |on_delayed_run_time_updated| is invoked when the delayed run time is
@@ -36,14 +36,17 @@
   ~DelayedTaskManager();
 
   // Adds |task| to a queue of delayed tasks. The task will be posted to
-  // |thread_pool| as part of |sequence| the first time that PostReadyTasks() is
-  // called while Now() is passed |task->delayed_run_time|.
+  // |thread_pool| with |sequence| and |worker_thread| the first time that
+  // PostReadyTasks() is called while Now() is passed |task->delayed_run_time|.
+  // |worker_thread| is a SchedulerWorkerThread owned by |thread_pool| or
+  // nullptr.
   //
-  // TODO(robliao): Find a concrete way to manage |thread_pool|'s memory. It is
-  // never deleted in production, but it is better not to spread this assumption
-  // throughout the scheduler.
+  // TODO(robliao): Find a concrete way to manage the memory of |worker_thread|
+  // and |thread_pool|. These objects are never deleted in production, but it is
+  // better not to spread this assumption throughout the scheduler.
   void AddDelayedTask(std::unique_ptr<Task> task,
                       scoped_refptr<Sequence> sequence,
+                      SchedulerWorkerThread* worker_thread,
                       SchedulerThreadPool* thread_pool);
 
   // Posts delayed tasks that are ripe for execution.
diff --git a/base/task_scheduler/delayed_task_manager_unittest.cc b/base/task_scheduler/delayed_task_manager_unittest.cc
index 706bb2b6..dc9c1577 100644
--- a/base/task_scheduler/delayed_task_manager_unittest.cc
+++ b/base/task_scheduler/delayed_task_manager_unittest.cc
@@ -59,17 +59,22 @@
   }
 
   bool PostTaskWithSequence(std::unique_ptr<Task> task,
-                            scoped_refptr<Sequence> sequence) override {
+                            scoped_refptr<Sequence> sequence,
+                            SchedulerWorkerThread* worker_thread) override {
     NOTREACHED();
     return true;
   }
 
   void PostTaskWithSequenceNow(std::unique_ptr<Task> task,
-                               scoped_refptr<Sequence> sequence) override {
-    PostTaskWithSequenceNowMock(task.get(), sequence.get());
+                               scoped_refptr<Sequence> sequence,
+                               SchedulerWorkerThread* worker_thread) override {
+    PostTaskWithSequenceNowMock(task.get(), sequence.get(), worker_thread);
   }
 
-  MOCK_METHOD2(PostTaskWithSequenceNowMock, void(const Task*, const Sequence*));
+  MOCK_METHOD3(PostTaskWithSequenceNowMock,
+               void(const Task*,
+                    const Sequence*,
+                    const SchedulerWorkerThread* worker_thread));
 };
 
 }  // namespace
@@ -95,7 +100,7 @@
 
   // Add |task| to the DelayedTaskManager.
   EXPECT_CALL(manager, OnDelayedRunTimeUpdated());
-  manager.AddDelayedTask(std::move(task), sequence, &thread_pool);
+  manager.AddDelayedTask(std::move(task), sequence, nullptr, &thread_pool);
   testing::Mock::VerifyAndClear(&manager);
   EXPECT_EQ(task_raw->delayed_run_time, manager.GetDelayedRunTime());
 
@@ -121,7 +126,7 @@
 
   // Add |task| to the DelayedTaskManager.
   EXPECT_CALL(manager, OnDelayedRunTimeUpdated());
-  manager.AddDelayedTask(std::move(task), sequence, &thread_pool);
+  manager.AddDelayedTask(std::move(task), sequence, nullptr, &thread_pool);
   testing::Mock::VerifyAndClear(&manager);
   EXPECT_EQ(task_raw->delayed_run_time, manager.GetDelayedRunTime());
 
@@ -130,7 +135,7 @@
 
   // Ask the DelayedTaskManager to post tasks that are ripe for execution.
   EXPECT_CALL(thread_pool,
-              PostTaskWithSequenceNowMock(task_raw, sequence.get()));
+              PostTaskWithSequenceNowMock(task_raw, sequence.get(), nullptr));
   manager.PostReadyTasks();
   testing::Mock::VerifyAndClear(&manager);
   EXPECT_EQ(TimeTicks(), manager.GetDelayedRunTime());
@@ -150,7 +155,7 @@
 
   // Add |task| to the DelayedTaskManager.
   EXPECT_CALL(manager, OnDelayedRunTimeUpdated());
-  manager.AddDelayedTask(std::move(task), sequence, &thread_pool);
+  manager.AddDelayedTask(std::move(task), sequence, nullptr, &thread_pool);
   testing::Mock::VerifyAndClear(&manager);
   EXPECT_EQ(task_raw->delayed_run_time, manager.GetDelayedRunTime());
 
@@ -160,7 +165,7 @@
 
   // Ask the DelayedTaskManager to post tasks that are ripe for execution.
   EXPECT_CALL(thread_pool,
-              PostTaskWithSequenceNowMock(task_raw, sequence.get()));
+              PostTaskWithSequenceNowMock(task_raw, sequence.get(), nullptr));
   manager.PostReadyTasks();
   testing::Mock::VerifyAndClear(&manager);
   EXPECT_EQ(TimeTicks(), manager.GetDelayedRunTime());
@@ -192,20 +197,20 @@
   // Add |task_a| to the DelayedTaskManager. The delayed run time should be
   // updated to |task_a|'s delayed run time.
   EXPECT_CALL(manager, OnDelayedRunTimeUpdated());
-  manager.AddDelayedTask(std::move(task_a), sequence, &thread_pool);
+  manager.AddDelayedTask(std::move(task_a), sequence, nullptr, &thread_pool);
   testing::Mock::VerifyAndClear(&manager);
   EXPECT_EQ(task_a_raw->delayed_run_time, manager.GetDelayedRunTime());
 
   // Add |task_b| to the DelayedTaskManager. The delayed run time shouldn't
   // change.
-  manager.AddDelayedTask(std::move(task_b), sequence, &thread_pool);
+  manager.AddDelayedTask(std::move(task_b), sequence, nullptr, &thread_pool);
   testing::Mock::VerifyAndClear(&manager);
   EXPECT_EQ(task_a_raw->delayed_run_time, manager.GetDelayedRunTime());
 
   // Add |task_c| to the DelayedTaskManager. The delayed run time should be
   // updated to |task_c|'s delayed run time.
   EXPECT_CALL(manager, OnDelayedRunTimeUpdated());
-  manager.AddDelayedTask(std::move(task_c), sequence, &thread_pool);
+  manager.AddDelayedTask(std::move(task_c), sequence, nullptr, &thread_pool);
   testing::Mock::VerifyAndClear(&manager);
   EXPECT_EQ(task_c_raw->delayed_run_time, manager.GetDelayedRunTime());
 
@@ -216,7 +221,7 @@
   // |task_c_raw| should be posted and the delayed run time should become
   // |task_a_raw|'s delayed run time.
   EXPECT_CALL(thread_pool,
-              PostTaskWithSequenceNowMock(task_c_raw, sequence.get()));
+              PostTaskWithSequenceNowMock(task_c_raw, sequence.get(), nullptr));
   manager.PostReadyTasks();
   testing::Mock::VerifyAndClear(&thread_pool);
   EXPECT_EQ(task_a_raw->delayed_run_time, manager.GetDelayedRunTime());
@@ -228,9 +233,9 @@
   // |task_a_raw| and |task_b_raw| should be posted and the delayed run time
   // should become a null TimeTicks.
   EXPECT_CALL(thread_pool,
-              PostTaskWithSequenceNowMock(task_a_raw, sequence.get()));
+              PostTaskWithSequenceNowMock(task_a_raw, sequence.get(), nullptr));
   EXPECT_CALL(thread_pool,
-              PostTaskWithSequenceNowMock(task_b_raw, sequence.get()));
+              PostTaskWithSequenceNowMock(task_b_raw, sequence.get(), nullptr));
   manager.PostReadyTasks();
   testing::Mock::VerifyAndClear(&thread_pool);
   EXPECT_EQ(TimeTicks(), manager.GetDelayedRunTime());
diff --git a/base/task_scheduler/scheduler_thread_pool.h b/base/task_scheduler/scheduler_thread_pool.h
index 2451474..9793162 100644
--- a/base/task_scheduler/scheduler_thread_pool.h
+++ b/base/task_scheduler/scheduler_thread_pool.h
@@ -17,6 +17,7 @@
 namespace base {
 namespace internal {
 
+class SchedulerWorkerThread;
 struct SequenceSortKey;
 
 // Interface for a thread pool.
@@ -37,16 +38,26 @@
   virtual void ReEnqueueSequence(scoped_refptr<Sequence> sequence,
                                  const SequenceSortKey& sequence_sort_key) = 0;
 
-  // Posts |task| to be executed as part of |sequence|.  Returns true if |task|
-  // is posted.
+  // Posts |task| to be executed as part of |sequence|. If |worker_thread| is
+  // non-null, |task| will be scheduled to run on it specifically (note:
+  // |worker_thread| must be owned by this SchedulerThreadPool); otherwise,
+  // |task| will be added to the pending shared work. Returns true if |task| is
+  // posted.
   virtual bool PostTaskWithSequence(std::unique_ptr<Task> task,
-                                    scoped_refptr<Sequence> sequence) = 0;
+                                    scoped_refptr<Sequence> sequence,
+                                    SchedulerWorkerThread* worker_thread) = 0;
 
-  // Posts |task| to be executed by this thread pool as part of |sequence|. The
-  // scheduler's TaskTracker must have allowed |task| to be posted before this
-  // is called. This must only be called after |task|'s delayed run time.
-  virtual void PostTaskWithSequenceNow(std::unique_ptr<Task> task,
-                                       scoped_refptr<Sequence> sequence) = 0;
+  // Posts |task| to be executed by this thread pool as part of |sequence|. If
+  // |worker_thread| is non-null, |task| will be scheduled to run on it
+  // specifically (note: |worker_thread| must be owned by this
+  // SchedulerThreadPool); otherwise, |task| will be added to the pending shared
+  // work. The scheduler's TaskTracker must have allowed |task| to be posted
+  // before this is called. This must only be called after |task|'s delayed run
+  // time.
+  virtual void PostTaskWithSequenceNow(
+      std::unique_ptr<Task> task,
+      scoped_refptr<Sequence> sequence,
+      SchedulerWorkerThread* worker_thread) = 0;
 };
 
 }  // namespace internal
diff --git a/base/task_scheduler/scheduler_thread_pool_impl.cc b/base/task_scheduler/scheduler_thread_pool_impl.cc
index 599c46b..b64405d 100644
--- a/base/task_scheduler/scheduler_thread_pool_impl.cc
+++ b/base/task_scheduler/scheduler_thread_pool_impl.cc
@@ -4,14 +4,15 @@
 
 #include "base/task_scheduler/scheduler_thread_pool_impl.h"
 
+#include <algorithm>
 #include <utility>
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/lazy_instance.h"
-#include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/sequenced_task_runner.h"
+#include "base/single_thread_task_runner.h"
 #include "base/task_scheduler/delayed_task_manager.h"
 #include "base/task_scheduler/task_tracker.h"
 #include "base/threading/thread_local.h"
@@ -25,6 +26,10 @@
 LazyInstance<ThreadLocalPointer<const SchedulerThreadPool>>::Leaky
     tls_current_thread_pool = LAZY_INSTANCE_INITIALIZER;
 
+// SchedulerWorkerThread that owns the current thread, if any.
+LazyInstance<ThreadLocalPointer<const SchedulerWorkerThread>>::Leaky
+    tls_current_worker_thread = LAZY_INSTANCE_INITIALIZER;
+
 // A task runner that runs tasks with the PARALLEL ExecutionMode.
 class SchedulerParallelTaskRunner : public TaskRunner {
  public:
@@ -42,7 +47,7 @@
     // Post the task as part of a one-off single-task Sequence.
     return thread_pool_->PostTaskWithSequence(
         WrapUnique(new Task(from_here, closure, traits_, delay)),
-        make_scoped_refptr(new Sequence));
+        make_scoped_refptr(new Sequence), nullptr);
   }
 
   bool RunsTasksOnCurrentThread() const override {
@@ -72,9 +77,10 @@
   bool PostDelayedTask(const tracked_objects::Location& from_here,
                        const Closure& closure,
                        TimeDelta delay) override {
-    // Post the task as part of |sequence|.
+    // Post the task as part of |sequence_|.
     return thread_pool_->PostTaskWithSequence(
-        WrapUnique(new Task(from_here, closure, traits_, delay)), sequence_);
+        WrapUnique(new Task(from_here, closure, traits_, delay)), sequence_,
+        nullptr);
   }
 
   bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
@@ -100,18 +106,88 @@
   DISALLOW_COPY_AND_ASSIGN(SchedulerSequencedTaskRunner);
 };
 
+// A task runner that runs tasks with the SINGLE_THREADED ExecutionMode.
+class SchedulerSingleThreadTaskRunner : public SingleThreadTaskRunner {
+ public:
+  // Constructs a SchedulerSingleThreadTaskRunner which can be used to post
+  // tasks so long as |thread_pool| and |worker_thread| are alive.
+  // TODO(robliao): Find a concrete way to manage the memory of |thread_pool|
+  // and |worker_thread|.
+  SchedulerSingleThreadTaskRunner(const TaskTraits& traits,
+                                  SchedulerThreadPool* thread_pool,
+                                  SchedulerWorkerThread* worker_thread)
+      : traits_(traits),
+        thread_pool_(thread_pool),
+        worker_thread_(worker_thread) {}
+
+  // SingleThreadTaskRunner:
+  bool PostDelayedTask(const tracked_objects::Location& from_here,
+                       const Closure& closure,
+                       TimeDelta delay) override {
+    // Post the task to be executed by |worker_thread_| as part of |sequence_|.
+    return thread_pool_->PostTaskWithSequence(
+        WrapUnique(new Task(from_here, closure, traits_, delay)), sequence_,
+        worker_thread_);
+  }
+
+  bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
+                                  const Closure& closure,
+                                  base::TimeDelta delay) override {
+    // Tasks are never nested within the task scheduler.
+    return PostDelayedTask(from_here, closure, delay);
+  }
+
+  bool RunsTasksOnCurrentThread() const override {
+    return tls_current_worker_thread.Get().Get() == worker_thread_;
+  }
+
+ private:
+  ~SchedulerSingleThreadTaskRunner() override = default;
+
+  // Sequence for all Tasks posted through this TaskRunner.
+  const scoped_refptr<Sequence> sequence_ = new Sequence;
+
+  const TaskTraits traits_;
+  SchedulerThreadPool* const thread_pool_;
+  SchedulerWorkerThread* const worker_thread_;
+
+  DISALLOW_COPY_AND_ASSIGN(SchedulerSingleThreadTaskRunner);
+};
+
+// Only used in DCHECKs.
+bool ContainsWorkerThread(
+    const std::vector<std::unique_ptr<SchedulerWorkerThread>>& worker_threads,
+    const SchedulerWorkerThread* worker_thread) {
+  auto it = std::find_if(
+      worker_threads.begin(), worker_threads.end(),
+      [worker_thread](const std::unique_ptr<SchedulerWorkerThread>& i) {
+        return i.get() == worker_thread;
+      });
+  return it != worker_threads.end();
+}
+
 }  // namespace
 
 class SchedulerThreadPoolImpl::SchedulerWorkerThreadDelegateImpl
     : public SchedulerWorkerThread::Delegate {
  public:
+  // |outer| owns the worker thread for which this delegate is constructed.
+  // |re_enqueue_sequence_callback| is invoked when ReEnqueueSequence() is
+  // called with a non-single-threaded Sequence. |shared_priority_queue| is a
+  // PriorityQueue whose transactions may overlap with the worker thread's
+  // single-threaded PriorityQueue's transactions.
   SchedulerWorkerThreadDelegateImpl(
       SchedulerThreadPoolImpl* outer,
-      const ReEnqueueSequenceCallback& re_enqueue_sequence_callback);
+      const ReEnqueueSequenceCallback& re_enqueue_sequence_callback,
+      const PriorityQueue* shared_priority_queue);
   ~SchedulerWorkerThreadDelegateImpl() override;
 
+  PriorityQueue* single_threaded_priority_queue() {
+    return &single_threaded_priority_queue_;
+  }
+
   // SchedulerWorkerThread::Delegate:
-  void OnMainEntry() override;
+  void OnMainEntry(SchedulerWorkerThread* worker_thread) override;
   scoped_refptr<Sequence> GetWork(
       SchedulerWorkerThread* worker_thread) override;
   void ReEnqueueSequence(scoped_refptr<Sequence> sequence) override;
@@ -120,6 +196,13 @@
   SchedulerThreadPoolImpl* outer_;
   const ReEnqueueSequenceCallback re_enqueue_sequence_callback_;
 
+  // Single-threaded PriorityQueue for the worker thread.
+  PriorityQueue single_threaded_priority_queue_;
+
+  // True if the last Sequence returned by GetWork() was extracted from
+  // |single_threaded_priority_queue_|.
+  bool last_sequence_is_single_threaded_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(SchedulerWorkerThreadDelegateImpl);
 };
 
@@ -129,6 +212,7 @@
   DCHECK(join_for_testing_returned_.IsSignaled() || worker_threads_.empty());
 }
 
+// static
 std::unique_ptr<SchedulerThreadPoolImpl> SchedulerThreadPoolImpl::Create(
     ThreadPriority thread_priority,
     size_t max_threads,
@@ -168,10 +252,21 @@
     case ExecutionMode::SEQUENCED:
       return make_scoped_refptr(new SchedulerSequencedTaskRunner(traits, this));
 
-    case ExecutionMode::SINGLE_THREADED:
-      // TODO(fdoray): Support SINGLE_THREADED TaskRunners.
-      NOTREACHED();
-      return nullptr;
+    case ExecutionMode::SINGLE_THREADED: {
+      // TODO(fdoray): Find a way to take load into account when assigning a
+      // SchedulerWorkerThread to a SingleThreadTaskRunner. Also, this code
+      // assumes that all SchedulerWorkerThreads are alive. Eventually, we might
+      // decide to tear down threads that haven't run tasks for a long time.
+      size_t worker_thread_index;
+      {
+        AutoSchedulerLock auto_lock(next_worker_thread_index_lock_);
+        worker_thread_index = next_worker_thread_index_;
+        next_worker_thread_index_ =
+            (next_worker_thread_index_ + 1) % worker_threads_.size();
+      }
+      return make_scoped_refptr(new SchedulerSingleThreadTaskRunner(
+          traits, this, worker_threads_[worker_thread_index].get()));
+    }
   }
 
   NOTREACHED();
@@ -199,18 +294,22 @@
 
 bool SchedulerThreadPoolImpl::PostTaskWithSequence(
     std::unique_ptr<Task> task,
-    scoped_refptr<Sequence> sequence) {
+    scoped_refptr<Sequence> sequence,
+    SchedulerWorkerThread* worker_thread) {
   DCHECK(task);
   DCHECK(sequence);
+  DCHECK(!worker_thread ||
+         ContainsWorkerThread(worker_threads_, worker_thread));
 
   if (!task_tracker_->WillPostTask(task.get()))
     return false;
 
   if (task->delayed_run_time.is_null()) {
-    PostTaskWithSequenceNow(std::move(task), std::move(sequence));
+    PostTaskWithSequenceNow(std::move(task), std::move(sequence),
+                            worker_thread);
   } else {
     delayed_task_manager_->AddDelayedTask(std::move(task), std::move(sequence),
-                                          this);
+                                          worker_thread, this);
   }
 
   return true;
@@ -218,79 +317,151 @@
 
 void SchedulerThreadPoolImpl::PostTaskWithSequenceNow(
     std::unique_ptr<Task> task,
-    scoped_refptr<Sequence> sequence) {
+    scoped_refptr<Sequence> sequence,
+    SchedulerWorkerThread* worker_thread) {
   DCHECK(task);
   DCHECK(sequence);
+  DCHECK(!worker_thread ||
+         ContainsWorkerThread(worker_threads_, worker_thread));
 
   // Confirm that |task| is ready to run (its delayed run time is either null or
   // in the past).
   DCHECK_LE(task->delayed_run_time, delayed_task_manager_->Now());
 
+  // Because |worker_thread| belongs to this thread pool, we know that the type
+  // of its delegate is SchedulerWorkerThreadDelegateImpl.
+  PriorityQueue* const priority_queue =
+      worker_thread
+          ? static_cast<SchedulerWorkerThreadDelegateImpl*>(
+                worker_thread->delegate())
+                ->single_threaded_priority_queue()
+          : &shared_priority_queue_;
+  DCHECK(priority_queue);
+
   const bool sequence_was_empty = sequence->PushTask(std::move(task));
   if (sequence_was_empty) {
-    // Insert |sequence| in |shared_priority_queue_| if it was empty before
-    // |task| was inserted into it. Otherwise, one of these must be true:
+    // Insert |sequence| in |priority_queue| if it was empty before |task| was
+    // inserted into it. Otherwise, one of these must be true:
     // - |sequence| is already in a PriorityQueue (not necessarily
     //   |shared_priority_queue_|), or,
     // - A worker thread is running a Task from |sequence|. It will insert
     //   |sequence| in a PriorityQueue once it's done running the Task.
     const auto sequence_sort_key = sequence->GetSortKey();
-    shared_priority_queue_.BeginTransaction()->Push(
+    priority_queue->BeginTransaction()->Push(
         WrapUnique(new PriorityQueue::SequenceAndSortKey(std::move(sequence),
                                                          sequence_sort_key)));
 
     // Wake up a worker thread to process |sequence|.
-    WakeUpOneThread();
+    if (worker_thread)
+      worker_thread->WakeUp();
+    else
+      WakeUpOneThread();
   }
 }
 
 SchedulerThreadPoolImpl::SchedulerWorkerThreadDelegateImpl::
     SchedulerWorkerThreadDelegateImpl(
         SchedulerThreadPoolImpl* outer,
-        const ReEnqueueSequenceCallback& re_enqueue_sequence_callback)
+        const ReEnqueueSequenceCallback& re_enqueue_sequence_callback,
+        const PriorityQueue* shared_priority_queue)
     : outer_(outer),
-      re_enqueue_sequence_callback_(re_enqueue_sequence_callback) {}
+      re_enqueue_sequence_callback_(re_enqueue_sequence_callback),
+      single_threaded_priority_queue_(shared_priority_queue) {}
 
 SchedulerThreadPoolImpl::SchedulerWorkerThreadDelegateImpl::
     ~SchedulerWorkerThreadDelegateImpl() = default;
 
-void SchedulerThreadPoolImpl::SchedulerWorkerThreadDelegateImpl::OnMainEntry() {
+void SchedulerThreadPoolImpl::SchedulerWorkerThreadDelegateImpl::OnMainEntry(
+    SchedulerWorkerThread* worker_thread) {
+#if DCHECK_IS_ON()
+  // Wait for |outer_->threads_created_| to avoid traversing
+  // |outer_->worker_threads_| while it is being filled by Initialize().
+  outer_->threads_created_.Wait();
+  DCHECK(ContainsWorkerThread(outer_->worker_threads_, worker_thread));
+#endif
+
+  DCHECK(!tls_current_worker_thread.Get().Get());
   DCHECK(!tls_current_thread_pool.Get().Get());
+  tls_current_worker_thread.Get().Set(worker_thread);
   tls_current_thread_pool.Get().Set(outer_);
 }
 
 scoped_refptr<Sequence>
 SchedulerThreadPoolImpl::SchedulerWorkerThreadDelegateImpl::GetWork(
     SchedulerWorkerThread* worker_thread) {
-  std::unique_ptr<PriorityQueue::Transaction> transaction(
-      outer_->shared_priority_queue_.BeginTransaction());
-  const auto& sequence_and_sort_key = transaction->Peek();
+  DCHECK(ContainsWorkerThread(outer_->worker_threads_, worker_thread));
 
-  if (sequence_and_sort_key.is_null()) {
-    // |transaction| is kept alive while |worker_thread| is added to
-    // |idle_worker_threads_stack_| to avoid this race:
-    // 1. This thread creates a Transaction, finds |shared_priority_queue_|
-    //    empty and ends the Transaction.
-    // 2. Other thread creates a Transaction, inserts a Sequence into
-    //    |shared_priority_queue_| and ends the Transaction. This can't happen
-    //    if the Transaction of step 1 is still active because because there can
-    //    only be one active Transaction per PriorityQueue at a time.
-    // 3. Other thread calls WakeUpOneThread(). No thread is woken up because
-    //    |idle_worker_threads_stack_| is empty.
-    // 4. This thread adds itself to |idle_worker_threads_stack_| and goes to
-    //    sleep. No thread runs the Sequence inserted in step 2.
-    outer_->AddToIdleWorkerThreadsStack(worker_thread);
-    return nullptr;
+  scoped_refptr<Sequence> sequence;
+  {
+    std::unique_ptr<PriorityQueue::Transaction> shared_transaction(
+        outer_->shared_priority_queue_.BeginTransaction());
+    const auto& shared_sequence_and_sort_key = shared_transaction->Peek();
+
+    std::unique_ptr<PriorityQueue::Transaction> single_threaded_transaction(
+        single_threaded_priority_queue_.BeginTransaction());
+    const auto& single_threaded_sequence_and_sort_key =
+        single_threaded_transaction->Peek();
+
+    if (shared_sequence_and_sort_key.is_null() &&
+        single_threaded_sequence_and_sort_key.is_null()) {
+      single_threaded_transaction.reset();
+
+      // |shared_transaction| is kept alive while |worker_thread| is added to
+      // |idle_worker_threads_stack_| to avoid this race:
+      // 1. This thread creates a Transaction, finds |shared_priority_queue_|
+      //    empty and ends the Transaction.
+      // 2. Other thread creates a Transaction, inserts a Sequence into
+      //    |shared_priority_queue_| and ends the Transaction. This can't happen
+      //    if the Transaction of step 1 is still active because because there
+      //    can only be one active Transaction per PriorityQueue at a time.
+      // 3. Other thread calls WakeUpOneThread(). No thread is woken up because
+      //    |idle_worker_threads_stack_| is empty.
+      // 4. This thread adds itself to |idle_worker_threads_stack_| and goes to
+      //    sleep. No thread runs the Sequence inserted in step 2.
+      outer_->AddToIdleWorkerThreadsStack(worker_thread);
+      return nullptr;
+    }
+
+    // True if both PriorityQueues have Sequences and the Sequence at the top of
+    // the shared PriorityQueue is more important.
+    const bool shared_sequence_is_more_important =
+        !shared_sequence_and_sort_key.is_null() &&
+        !single_threaded_sequence_and_sort_key.is_null() &&
+        shared_sequence_and_sort_key.sort_key >
+            single_threaded_sequence_and_sort_key.sort_key;
+
+    if (single_threaded_sequence_and_sort_key.is_null() ||
+        shared_sequence_is_more_important) {
+      sequence = shared_sequence_and_sort_key.sequence;
+      shared_transaction->Pop();
+      last_sequence_is_single_threaded_ = false;
+    } else {
+      DCHECK(!single_threaded_sequence_and_sort_key.is_null());
+      sequence = single_threaded_sequence_and_sort_key.sequence;
+      single_threaded_transaction->Pop();
+      last_sequence_is_single_threaded_ = true;
+    }
   }
+  DCHECK(sequence);
 
-  scoped_refptr<Sequence> sequence = sequence_and_sort_key.sequence;
-  transaction->Pop();
+  outer_->RemoveFromIdleWorkerThreadsStack(worker_thread);
   return sequence;
 }
 
 void SchedulerThreadPoolImpl::SchedulerWorkerThreadDelegateImpl::
     ReEnqueueSequence(scoped_refptr<Sequence> sequence) {
-  re_enqueue_sequence_callback_.Run(std::move(sequence));
+  if (last_sequence_is_single_threaded_) {
+    // A single-threaded Sequence is always re-enqueued in the single-threaded
+    // PriorityQueue from which it was extracted.
+    const SequenceSortKey sequence_sort_key = sequence->GetSortKey();
+    single_threaded_priority_queue_.BeginTransaction()->Push(
+        WrapUnique(new PriorityQueue::SequenceAndSortKey(std::move(sequence),
+                                                         sequence_sort_key)));
+  } else {
+    // |re_enqueue_sequence_callback_| will determine in which PriorityQueue
+    // |sequence| must be enqueued.
+    re_enqueue_sequence_callback_.Run(std::move(sequence));
+  }
 }
 
 SchedulerThreadPoolImpl::SchedulerThreadPoolImpl(
@@ -300,6 +471,9 @@
       idle_worker_threads_stack_cv_for_testing_(
           idle_worker_threads_stack_lock_.CreateConditionVariable()),
       join_for_testing_returned_(true, false),
+#if DCHECK_IS_ON()
+      threads_created_(true, false),
+#endif
       task_tracker_(task_tracker),
       delayed_task_manager_(delayed_task_manager) {
   DCHECK(task_tracker_);
@@ -317,8 +491,9 @@
   for (size_t i = 0; i < max_threads; ++i) {
     std::unique_ptr<SchedulerWorkerThread> worker_thread =
         SchedulerWorkerThread::Create(
-            thread_priority, WrapUnique(new SchedulerWorkerThreadDelegateImpl(
-                                 this, re_enqueue_sequence_callback)),
+            thread_priority,
+            WrapUnique(new SchedulerWorkerThreadDelegateImpl(
+                this, re_enqueue_sequence_callback, &shared_priority_queue_)),
             task_tracker_);
     if (!worker_thread)
       break;
@@ -326,6 +501,10 @@
     worker_threads_.push_back(std::move(worker_thread));
   }
 
+#if DCHECK_IS_ON()
+  threads_created_.Signal();
+#endif
+
   return !worker_threads_.empty();
 }
 
@@ -349,5 +528,11 @@
     idle_worker_threads_stack_cv_for_testing_->Broadcast();
 }
 
+void SchedulerThreadPoolImpl::RemoveFromIdleWorkerThreadsStack(
+    SchedulerWorkerThread* worker_thread) {
+  AutoSchedulerLock auto_lock(idle_worker_threads_stack_lock_);
+  idle_worker_threads_stack_.Remove(worker_thread);
+}
+
 }  // namespace internal
 }  // namespace base
diff --git a/base/task_scheduler/scheduler_thread_pool_impl.h b/base/task_scheduler/scheduler_thread_pool_impl.h
index b764f27..13fba7e5 100644
--- a/base/task_scheduler/scheduler_thread_pool_impl.h
+++ b/base/task_scheduler/scheduler_thread_pool_impl.h
@@ -12,6 +12,7 @@
 
 #include "base/base_export.h"
 #include "base/callback.h"
+#include "base/logging.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/synchronization/condition_variable.h"
@@ -72,16 +73,17 @@
   void ReEnqueueSequence(scoped_refptr<Sequence> sequence,
                          const SequenceSortKey& sequence_sort_key) override;
   bool PostTaskWithSequence(std::unique_ptr<Task> task,
-                            scoped_refptr<Sequence> sequence) override;
+                            scoped_refptr<Sequence> sequence,
+                            SchedulerWorkerThread* worker_thread) override;
   void PostTaskWithSequenceNow(std::unique_ptr<Task> task,
-                               scoped_refptr<Sequence> sequence) override;
+                               scoped_refptr<Sequence> sequence,
+                               SchedulerWorkerThread* worker_thread) override;
 
  private:
   class SchedulerWorkerThreadDelegateImpl;
 
-  SchedulerThreadPoolImpl(
-      TaskTracker* task_tracker,
-      DelayedTaskManager* delayed_task_manager);
+  SchedulerThreadPoolImpl(TaskTracker* task_tracker,
+                          DelayedTaskManager* delayed_task_manager);
 
   bool Initialize(
       ThreadPriority thread_priority,
@@ -94,13 +96,23 @@
   // Adds |worker_thread| to |idle_worker_threads_stack_|.
   void AddToIdleWorkerThreadsStack(SchedulerWorkerThread* worker_thread);
 
-  // PriorityQueue from which all threads of this thread pool get work.
-  PriorityQueue shared_priority_queue_;
+  // Removes |worker_thread| from |idle_worker_threads_stack_|.
+  void RemoveFromIdleWorkerThreadsStack(SchedulerWorkerThread* worker_thread);
 
   // All worker threads owned by this thread pool. Only modified during
   // initialization of the thread pool.
   std::vector<std::unique_ptr<SchedulerWorkerThread>> worker_threads_;
 
+  // Synchronizes access to |next_worker_thread_index_|.
+  SchedulerLock next_worker_thread_index_lock_;
+
+  // Index of the worker thread that will be assigned to the next single-
+  // threaded TaskRunner returned by this pool.
+  size_t next_worker_thread_index_ = 0;
+
+  // PriorityQueue from which all threads of this thread pool get work.
+  PriorityQueue shared_priority_queue_;
+
   // Synchronizes access to |idle_worker_threads_stack_| and
   // |idle_worker_threads_stack_cv_for_testing_|. Has |shared_priority_queue_|'s
   // lock as its predecessor so that a thread can be pushed to
@@ -117,6 +129,11 @@
   // Signaled once JoinForTesting() has returned.
   WaitableEvent join_for_testing_returned_;
 
+#if DCHECK_IS_ON()
+  // Signaled when all threads have been created.
+  WaitableEvent threads_created_;
+#endif
+
   TaskTracker* const task_tracker_;
   DelayedTaskManager* const delayed_task_manager_;
 
diff --git a/base/task_scheduler/scheduler_thread_pool_impl_unittest.cc b/base/task_scheduler/scheduler_thread_pool_impl_unittest.cc
index 691d0dd..3eb003e 100644
--- a/base/task_scheduler/scheduler_thread_pool_impl_unittest.cc
+++ b/base/task_scheduler/scheduler_thread_pool_impl_unittest.cc
@@ -314,6 +314,9 @@
 INSTANTIATE_TEST_CASE_P(Sequenced,
                         TaskSchedulerThreadPoolImplTest,
                         ::testing::Values(ExecutionMode::SEQUENCED));
+INSTANTIATE_TEST_CASE_P(SingleThreaded,
+                        TaskSchedulerThreadPoolImplTest,
+                        ::testing::Values(ExecutionMode::SINGLE_THREADED));
 
 }  // namespace internal
 }  // namespace base
diff --git a/base/task_scheduler/scheduler_worker_thread.cc b/base/task_scheduler/scheduler_worker_thread.cc
index 11c88af..c015bd86 100644
--- a/base/task_scheduler/scheduler_worker_thread.cc
+++ b/base/task_scheduler/scheduler_worker_thread.cc
@@ -59,7 +59,7 @@
 }
 
 void SchedulerWorkerThread::ThreadMain() {
-  delegate_->OnMainEntry();
+  delegate_->OnMainEntry(this);
 
   // A SchedulerWorkerThread starts out sleeping.
   wake_up_event_.Wait();
diff --git a/base/task_scheduler/scheduler_worker_thread.h b/base/task_scheduler/scheduler_worker_thread.h
index 3022d100..5de245dc 100644
--- a/base/task_scheduler/scheduler_worker_thread.h
+++ b/base/task_scheduler/scheduler_worker_thread.h
@@ -37,8 +37,8 @@
    public:
     virtual ~Delegate() = default;
 
-    // Called when the main function of the SchedulerWorkerThread enters.
-    virtual void OnMainEntry() = 0;
+    // Called by |worker_thread| when it enters its main function.
+    virtual void OnMainEntry(SchedulerWorkerThread* worker_thread) = 0;
 
     // Called by |worker_thread| to get a Sequence from which to run a Task.
     virtual scoped_refptr<Sequence> GetWork(
@@ -68,6 +68,8 @@
   // returned by the GetWork() method of its delegate until it returns nullptr.
   void WakeUp();
 
+  SchedulerWorkerThread::Delegate* delegate() { return delegate_.get(); }
+
   // Joins this SchedulerWorkerThread. If a Task is already running, it will be
   // allowed to complete its execution. This can only be called once.
   void JoinForTesting();
diff --git a/base/task_scheduler/scheduler_worker_thread_stack_unittest.cc b/base/task_scheduler/scheduler_worker_thread_stack_unittest.cc
index b39243d0..50422140 100644
--- a/base/task_scheduler/scheduler_worker_thread_stack_unittest.cc
+++ b/base/task_scheduler/scheduler_worker_thread_stack_unittest.cc
@@ -22,7 +22,7 @@
 class MockSchedulerWorkerThreadDelegate
     : public SchedulerWorkerThread::Delegate {
  public:
-  void OnMainEntry() override {}
+  void OnMainEntry(SchedulerWorkerThread* worker_thread) override {}
   scoped_refptr<Sequence> GetWork(
       SchedulerWorkerThread* worker_thread) override {
     return nullptr;
diff --git a/base/task_scheduler/scheduler_worker_thread_unittest.cc b/base/task_scheduler/scheduler_worker_thread_unittest.cc
index 36fa423..2a9d5c6 100644
--- a/base/task_scheduler/scheduler_worker_thread_unittest.cc
+++ b/base/task_scheduler/scheduler_worker_thread_unittest.cc
@@ -31,7 +31,8 @@
  protected:
   TaskSchedulerWorkerThreadTest()
       : main_entry_called_(true, false),
-        num_get_work_cv_(lock_.CreateConditionVariable()) {}
+        num_get_work_cv_(lock_.CreateConditionVariable()),
+        worker_thread_set_(true, false) {}
 
   void SetUp() override {
     worker_thread_ = SchedulerWorkerThread::Create(
@@ -39,6 +40,7 @@
         WrapUnique(new TestSchedulerWorkerThreadDelegate(this)),
         &task_tracker_);
     ASSERT_TRUE(worker_thread_);
+    worker_thread_set_.Signal();
     main_entry_called_.Wait();
   }
 
@@ -91,7 +93,10 @@
         : outer_(outer) {}
 
     // SchedulerWorkerThread::Delegate:
-    void OnMainEntry() override {
+    void OnMainEntry(SchedulerWorkerThread* worker_thread) override {
+      outer_->worker_thread_set_.Wait();
+      EXPECT_EQ(outer_->worker_thread_.get(), worker_thread);
+
       // Without synchronization, OnMainEntry() could be called twice without
       // generating an error.
       AutoSchedulerLock auto_lock(outer_->lock_);
@@ -200,6 +205,9 @@
   // Number of times that RunTaskCallback() has been called.
   size_t num_run_tasks_ = 0;
 
+  // Signaled after |worker_thread_| is set.
+  WaitableEvent worker_thread_set_;
+
   DISALLOW_COPY_AND_ASSIGN(TaskSchedulerWorkerThreadTest);
 };
 
diff --git a/blimp/client/app/android/java/src/org/chromium/blimp/BlimpLibraryLoader.java b/blimp/client/app/android/java/src/org/chromium/blimp/BlimpLibraryLoader.java
index 3463887..290c4dbb 100644
--- a/blimp/client/app/android/java/src/org/chromium/blimp/BlimpLibraryLoader.java
+++ b/blimp/client/app/android/java/src/org/chromium/blimp/BlimpLibraryLoader.java
@@ -7,7 +7,6 @@
 import android.content.Context;
 import android.os.Handler;
 
-import org.chromium.base.ContextUtils;
 import org.chromium.base.ObserverList;
 import org.chromium.base.ResourceExtractor;
 import org.chromium.base.ThreadUtils;
@@ -91,7 +90,6 @@
         extractor.addCompletionCallback(new Runnable() {
             @Override
             public void run() {
-                ContextUtils.initApplicationContext(context.getApplicationContext());
                 new Handler().post(new Runnable() {
                     @Override
                     public void run() {
diff --git a/cc/layers/draw_properties.cc b/cc/layers/draw_properties.cc
index 909ef47..165dc26 100644
--- a/cc/layers/draw_properties.cc
+++ b/cc/layers/draw_properties.cc
@@ -12,7 +12,6 @@
       can_use_lcd_text(false),
       is_clipped(false),
       num_unclipped_descendants(0),
-      last_drawn_render_surface_layer_list_id(0),
       maximum_animation_contents_scale(0.f),
       starting_animation_contents_scale(0.f) {}
 
diff --git a/cc/layers/draw_properties.h b/cc/layers/draw_properties.h
index 59acede..866bc53 100644
--- a/cc/layers/draw_properties.h
+++ b/cc/layers/draw_properties.h
@@ -66,15 +66,6 @@
   // does not include our clip children because they are clipped by us.
   size_t num_unclipped_descendants;
 
-  // Each time we generate a new render surface layer list, an ID is used to
-  // identify it. |last_drawn_render_surface_layer_list_id| is set to the ID
-  // that marked the render surface layer list generation which last updated
-  // these draw properties and determined that this layer will draw itself.
-  // If these draw properties are not a part of the render surface layer list,
-  // or the layer doesn't contribute anything, then this ID will be either out
-  // of date or 0.
-  int last_drawn_render_surface_layer_list_id;
-
   // The maximum scale during the layers current animation at which content
   // should be rastered at to be crisp.
   float maximum_animation_contents_scale;
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
index d238c3c..9b7f532 100644
--- a/cc/layers/layer_impl.cc
+++ b/cc/layers/layer_impl.cc
@@ -65,6 +65,7 @@
       use_local_transform_for_backface_visibility_(false),
       should_check_backface_visibility_(false),
       draws_content_(false),
+      is_drawn_render_surface_layer_list_member_(false),
       hide_layer_and_subtree_(false),
       is_affected_by_page_scale_(true),
       was_ever_ready_since_last_transform_animation_(true),
@@ -1294,11 +1295,6 @@
   }
 }
 
-bool LayerImpl::IsDrawnRenderSurfaceLayerListMember() const {
-  return draw_properties_.last_drawn_render_surface_layer_list_id ==
-         layer_tree_impl_->current_render_surface_list_id();
-}
-
 size_t LayerImpl::GPUMemoryUsageInBytes() const { return 0; }
 
 void LayerImpl::RunMicroBenchmark(MicroBenchmarkImpl* benchmark) {
@@ -1318,7 +1314,7 @@
 
 gfx::Transform LayerImpl::DrawTransform() const {
   // Only drawn layers have up-to-date draw properties.
-  if (!IsDrawnRenderSurfaceLayerListMember()) {
+  if (!is_drawn_render_surface_layer_list_member()) {
     if (layer_tree_impl()->property_trees()->non_root_surfaces_enabled) {
       return draw_property_utils::DrawTransform(
           this, layer_tree_impl()->property_trees()->transform_tree);
@@ -1333,7 +1329,7 @@
 
 gfx::Transform LayerImpl::ScreenSpaceTransform() const {
   // Only drawn layers have up-to-date draw properties.
-  if (!IsDrawnRenderSurfaceLayerListMember()) {
+  if (!is_drawn_render_surface_layer_list_member()) {
     return draw_property_utils::ScreenSpaceTransform(
         this, layer_tree_impl()->property_trees()->transform_tree);
   }
diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h
index 119cfbfb..8f72d02 100644
--- a/cc/layers/layer_impl.h
+++ b/cc/layers/layer_impl.h
@@ -473,7 +473,13 @@
   void SetDebugInfo(
       std::unique_ptr<base::trace_event::ConvertableToTraceFormat> debug_info);
 
-  bool IsDrawnRenderSurfaceLayerListMember() const;
+  void set_is_drawn_render_surface_layer_list_member(bool is_member) {
+    is_drawn_render_surface_layer_list_member_ = is_member;
+  }
+
+  bool is_drawn_render_surface_layer_list_member() const {
+    return is_drawn_render_surface_layer_list_member_;
+  }
 
   void Set3dSortingContextId(int id);
   int sorting_context_id() { return sorting_context_id_; }
@@ -595,6 +601,7 @@
   bool use_local_transform_for_backface_visibility_ : 1;
   bool should_check_backface_visibility_ : 1;
   bool draws_content_ : 1;
+  bool is_drawn_render_surface_layer_list_member_ : 1;
   bool hide_layer_and_subtree_ : 1;
 
   bool is_affected_by_page_scale_ : 1;
diff --git a/cc/layers/layer_iterator_unittest.cc b/cc/layers/layer_iterator_unittest.cc
index a8ad64b4..9c23d32 100644
--- a/cc/layers/layer_iterator_unittest.cc
+++ b/cc/layers/layer_iterator_unittest.cc
@@ -139,10 +139,8 @@
   host_impl_.active_tree()->SetRootLayer(std::move(root_layer));
 
   LayerImplList render_surface_layer_list;
-  host_impl_.active_tree()->IncrementRenderSurfaceListIdForTesting();
   LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
-      root_ptr, root_ptr->bounds(), &render_surface_layer_list,
-      host_impl_.active_tree()->current_render_surface_list_id());
+      root_ptr, root_ptr->bounds(), &render_surface_layer_list);
   LayerTreeHostCommon::CalculateDrawProperties(&inputs);
 
   IterateFrontToBack(&render_surface_layer_list);
@@ -186,10 +184,8 @@
   host_impl_.active_tree()->SetRootLayer(std::move(root_layer));
 
   LayerImplList render_surface_layer_list;
-  host_impl_.active_tree()->IncrementRenderSurfaceListIdForTesting();
   LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
-      root_ptr, root_ptr->bounds(), &render_surface_layer_list,
-      host_impl_.active_tree()->current_render_surface_list_id());
+      root_ptr, root_ptr->bounds(), &render_surface_layer_list);
   LayerTreeHostCommon::CalculateDrawProperties(&inputs);
 
   IterateFrontToBack(&render_surface_layer_list);
@@ -241,10 +237,8 @@
   host_impl_.active_tree()->SetRootLayer(std::move(root_layer));
 
   LayerImplList render_surface_layer_list;
-  host_impl_.active_tree()->IncrementRenderSurfaceListIdForTesting();
   LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
-      root_ptr, root_ptr->bounds(), &render_surface_layer_list,
-      host_impl_.active_tree()->current_render_surface_list_id());
+      root_ptr, root_ptr->bounds(), &render_surface_layer_list);
   LayerTreeHostCommon::CalculateDrawProperties(&inputs);
 
   IterateFrontToBack(&render_surface_layer_list);
diff --git a/cc/layers/layer_position_constraint_unittest.cc b/cc/layers/layer_position_constraint_unittest.cc
index c274383e..104d8e618 100644
--- a/cc/layers/layer_position_constraint_unittest.cc
+++ b/cc/layers/layer_position_constraint_unittest.cc
@@ -48,10 +48,8 @@
 
 void ExecuteCalculateDrawProperties(LayerImpl* root_layer) {
   std::vector<LayerImpl*> dummy_render_surface_layer_list;
-  root_layer->layer_tree_impl()->IncrementRenderSurfaceListIdForTesting();
   LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
-      root_layer, root_layer->bounds(), &dummy_render_surface_layer_list,
-      root_layer->layer_tree_impl()->current_render_surface_list_id());
+      root_layer, root_layer->bounds(), &dummy_render_surface_layer_list);
   inputs.inner_viewport_scroll_layer =
       root_layer->layer_tree_impl()->InnerViewportScrollLayer();
   inputs.outer_viewport_scroll_layer =
diff --git a/cc/layers/picture_image_layer_impl_unittest.cc b/cc/layers/picture_image_layer_impl_unittest.cc
index 8564d1c..35dd44b 100644
--- a/cc/layers/picture_image_layer_impl_unittest.cc
+++ b/cc/layers/picture_image_layer_impl_unittest.cc
@@ -89,6 +89,7 @@
     gfx::Transform scale_transform;
     scale_transform.Scale(ideal_contents_scale, ideal_contents_scale);
     layer->draw_properties().target_space_transform = scale_transform;
+    layer->set_is_drawn_render_surface_layer_list_member(true);
     DCHECK_EQ(layer->GetIdealContentsScale(), ideal_contents_scale);
     layer->draw_properties().maximum_animation_contents_scale =
         maximum_animation_contents_scale;
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc
index 5f2c1dd..a96a90d 100644
--- a/cc/layers/picture_layer_impl.cc
+++ b/cc/layers/picture_layer_impl.cc
@@ -1280,7 +1280,8 @@
 }
 
 bool PictureLayerImpl::HasValidTilePriorities() const {
-  return IsOnActiveOrPendingTree() && IsDrawnRenderSurfaceLayerListMember();
+  return IsOnActiveOrPendingTree() &&
+         is_drawn_render_surface_layer_list_member();
 }
 
 }  // namespace cc
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc
index 9fe181b..12fc720 100644
--- a/cc/layers/picture_layer_impl_unittest.cc
+++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -280,6 +280,7 @@
     gfx::Transform scale_transform;
     scale_transform.Scale(ideal_contents_scale, ideal_contents_scale);
     layer->draw_properties().target_space_transform = scale_transform;
+    layer->set_is_drawn_render_surface_layer_list_member(true);
     DCHECK_EQ(layer->GetIdealContentsScale(), ideal_contents_scale);
     layer->draw_properties().maximum_animation_contents_scale =
         maximum_animation_contents_scale;
diff --git a/cc/layers/render_surface_unittest.cc b/cc/layers/render_surface_unittest.cc
index 2c211779..da440c0b 100644
--- a/cc/layers/render_surface_unittest.cc
+++ b/cc/layers/render_surface_unittest.cc
@@ -105,6 +105,8 @@
   RenderSurfaceImpl* render_surface = owning_layer->render_surface();
 
   root_layer->AddChild(std::move(owning_layer));
+  host_impl.active_tree()->SetRootLayer(std::move(root_layer));
+  host_impl.active_tree()->BuildPropertyTreesForTesting();
 
   gfx::Rect content_rect(0, 0, 50, 50);
   gfx::Rect clip_rect(5, 5, 40, 40);
diff --git a/cc/layers/video_layer_impl_unittest.cc b/cc/layers/video_layer_impl_unittest.cc
index eda59e7a..43df376d 100644
--- a/cc/layers/video_layer_impl_unittest.cc
+++ b/cc/layers/video_layer_impl_unittest.cc
@@ -312,6 +312,7 @@
       impl.AddChildToRoot<VideoLayerImpl>(&provider, media::VIDEO_ROTATION_0);
   video_layer_impl->SetBounds(layer_size);
   video_layer_impl->SetDrawsContent(true);
+  impl.host_impl()->active_tree()->BuildPropertyTreesForTesting();
 
   gfx::Rect occluded;
   impl.AppendQuadsWithOcclusion(video_layer_impl, occluded);
@@ -353,6 +354,7 @@
       impl.AddChildToRoot<VideoLayerImpl>(&provider, media::VIDEO_ROTATION_0);
   video_layer_impl->SetBounds(layer_size);
   video_layer_impl->SetDrawsContent(true);
+  impl.host_impl()->active_tree()->BuildPropertyTreesForTesting();
 
   gfx::Rect occluded;
   impl.AppendQuadsWithOcclusion(video_layer_impl, occluded);
diff --git a/cc/playback/image_hijack_canvas.cc b/cc/playback/image_hijack_canvas.cc
index f0fc139..15c42a7 100644
--- a/cc/playback/image_hijack_canvas.cc
+++ b/cc/playback/image_hijack_canvas.cc
@@ -4,9 +4,9 @@
 
 #include "cc/playback/image_hijack_canvas.h"
 
+#include "base/optional.h"
 #include "cc/playback/discardable_image_map.h"
 #include "cc/tiles/image_decode_controller.h"
-#include "third_party/skia/include/core/SkTLazy.h"
 
 namespace cc {
 namespace {
@@ -32,9 +32,10 @@
         decoded_draw_image_(
             image_decode_controller_->GetDecodedImageForDraw(draw_image_)) {
     DCHECK(draw_image_.image()->isLazyGenerated());
-    if (paint)
-      decoded_paint_.set(*paint)->setFilterQuality(
-          decoded_draw_image_.filter_quality());
+    if (paint) {
+      decoded_paint_ = *paint;
+      decoded_paint_->setFilterQuality(decoded_draw_image_.filter_quality());
+    }
   }
 
   ~ScopedDecodedImageLock() {
@@ -43,14 +44,15 @@
   }
 
   const DecodedDrawImage& decoded_image() const { return decoded_draw_image_; }
-  const SkPaint* decoded_paint() const { return decoded_paint_.getMaybeNull(); }
+  const SkPaint* decoded_paint() const {
+    return decoded_paint_ ? &decoded_paint_.value() : nullptr;
+  }
 
  private:
   ImageDecodeController* image_decode_controller_;
   DrawImage draw_image_;
   DecodedDrawImage decoded_draw_image_;
-  // TODO(fmalita): use base::Optional when it becomes available
-  SkTLazy<SkPaint> decoded_paint_;
+  base::Optional<SkPaint> decoded_paint_;
 };
 
 }  // namespace
diff --git a/cc/playback/raster_source.cc b/cc/playback/raster_source.cc
index 38a83b9a3..7f80f9a 100644
--- a/cc/playback/raster_source.cc
+++ b/cc/playback/raster_source.cc
@@ -18,7 +18,6 @@
 #include "skia/ext/analysis_canvas.h"
 #include "third_party/skia/include/core/SkCanvas.h"
 #include "third_party/skia/include/core/SkPictureRecorder.h"
-#include "third_party/skia/include/core/SkTLazy.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 
 namespace cc {
diff --git a/cc/test/fake_picture_layer_impl.cc b/cc/test/fake_picture_layer_impl.cc
index 87631cd..65297112 100644
--- a/cc/test/fake_picture_layer_impl.cc
+++ b/cc/test/fake_picture_layer_impl.cc
@@ -119,12 +119,6 @@
   UpdateRasterSource(raster_source, &invalidation_temp, pending_set);
 }
 
-void FakePictureLayerImpl::SetIsDrawnRenderSurfaceLayerListMember(bool is) {
-  draw_properties().last_drawn_render_surface_layer_list_id =
-      is ? layer_tree_impl()->current_render_surface_list_id()
-         : layer_tree_impl()->current_render_surface_list_id() - 1;
-}
-
 void FakePictureLayerImpl::CreateAllTiles() {
   for (size_t i = 0; i < num_tilings(); ++i)
     tilings_->tiling_at(i)->CreateAllTilesForTesting();
diff --git a/cc/test/fake_picture_layer_impl.h b/cc/test/fake_picture_layer_impl.h
index d9ae10b..3ae72a2a 100644
--- a/cc/test/fake_picture_layer_impl.h
+++ b/cc/test/fake_picture_layer_impl.h
@@ -125,8 +125,6 @@
 
   void set_fixed_tile_size(const gfx::Size& size) { fixed_tile_size_ = size; }
 
-  void SetIsDrawnRenderSurfaceLayerListMember(bool is);
-
   void CreateAllTiles();
   void SetAllTilesReady();
   void SetAllTilesReadyInTiling(PictureLayerTiling* tiling);
diff --git a/cc/test/layer_test_common.cc b/cc/test/layer_test_common.cc
index 23b4144..af7ffeb8 100644
--- a/cc/test/layer_test_common.cc
+++ b/cc/test/layer_test_common.cc
@@ -150,10 +150,8 @@
 void LayerTestCommon::LayerImplTest::CalcDrawProps(
     const gfx::Size& viewport_size) {
   LayerImplList layer_list;
-  host_->host_impl()->active_tree()->IncrementRenderSurfaceListIdForTesting();
   LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
-      root_layer(), viewport_size, &layer_list,
-      host_->host_impl()->active_tree()->current_render_surface_list_id());
+      root_layer(), viewport_size, &layer_list);
   LayerTreeHostCommon::CalculateDrawProperties(&inputs);
 }
 
diff --git a/cc/test/layer_tree_host_common_test.cc b/cc/test/layer_tree_host_common_test.cc
index 9a4291c..6ac0c57 100644
--- a/cc/test/layer_tree_host_common_test.cc
+++ b/cc/test/layer_tree_host_common_test.cc
@@ -16,9 +16,7 @@
 namespace cc {
 LayerTreeHostCommonTestBase::LayerTreeHostCommonTestBase(
     const LayerTreeSettings& settings)
-    : LayerTestCommon::LayerImplTest(settings),
-      render_surface_layer_list_count_(0) {
-}
+    : LayerTestCommon::LayerImplTest(settings) {}
 
 LayerTreeHostCommonTestBase::~LayerTreeHostCommonTestBase() {
 }
@@ -191,10 +189,8 @@
   // We are probably not testing what is intended if the root_layer bounds are
   // empty.
   DCHECK(!root_layer->bounds().IsEmpty());
-  root_layer->layer_tree_impl()->IncrementRenderSurfaceListIdForTesting();
   LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
-      root_layer, device_viewport_size, render_surface_layer_list_impl_.get(),
-      root_layer->layer_tree_impl()->current_render_surface_list_id());
+      root_layer, device_viewport_size, render_surface_layer_list_impl_.get());
   inputs.device_scale_factor = device_scale_factor;
   inputs.page_scale_factor = page_scale_factor;
   inputs.page_scale_layer = page_scale_layer;
@@ -202,9 +198,6 @@
   inputs.layers_always_allowed_lcd_text = layers_always_allowed_lcd_text;
   inputs.can_adjust_raster_scales = true;
 
-  render_surface_layer_list_count_ =
-      inputs.current_render_surface_layer_list_id;
-
   LayerTreeHostCommon::CalculateDrawProperties(&inputs);
 }
 
@@ -217,16 +210,11 @@
   render_surface_layer_list_impl_.reset(new LayerImplList);
 
   DCHECK(!root_layer->bounds().IsEmpty());
-  root_layer->layer_tree_impl()->IncrementRenderSurfaceListIdForTesting();
   LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
-      root_layer, device_viewport_size, render_surface_layer_list_impl_.get(),
-      root_layer->layer_tree_impl()->current_render_surface_list_id());
+      root_layer, device_viewport_size, render_surface_layer_list_impl_.get());
   inputs.can_adjust_raster_scales = true;
   inputs.can_render_to_separate_surface = false;
 
-  render_surface_layer_list_count_ =
-      inputs.current_render_surface_layer_list_id;
-
   LayerTreeHostCommon::CalculateDrawProperties(&inputs);
 }
 
diff --git a/cc/test/layer_tree_host_common_test.h b/cc/test/layer_tree_host_common_test.h
index a91dc9b..45a42b8 100644
--- a/cc/test/layer_tree_host_common_test.h
+++ b/cc/test/layer_tree_host_common_test.h
@@ -134,16 +134,10 @@
   const LayerList& update_layer_list() const { return update_layer_list_; }
   bool UpdateLayerListContains(int id) const;
 
-  int render_surface_layer_list_count() const {
-    return render_surface_layer_list_count_;
-  }
-
  private:
   std::unique_ptr<std::vector<LayerImpl*>> render_surface_layer_list_impl_;
   LayerList update_layer_list_;
   std::unique_ptr<LayerImplList> update_layer_list_impl_;
-
-  int render_surface_layer_list_count_;
 };
 
 class LayerTreeHostCommonTest : public LayerTreeHostCommonTestBase,
diff --git a/cc/tiles/tile_manager_unittest.cc b/cc/tiles/tile_manager_unittest.cc
index c22a974..a691b44 100644
--- a/cc/tiles/tile_manager_unittest.cc
+++ b/cc/tiles/tile_manager_unittest.cc
@@ -1558,6 +1558,7 @@
 
   std::unique_ptr<PictureLayerImpl> layer_impl =
       PictureLayerImpl::Create(host_impl_.active_tree(), 1, false);
+  layer_impl->set_is_drawn_render_surface_layer_list_member(true);
   PictureLayerTilingSet* tiling_set = layer_impl->picture_layer_tiling_set();
 
   PictureLayerTiling* tiling = tiling_set->AddTiling(1.0f, raster_source);
@@ -1788,6 +1789,7 @@
     std::unique_ptr<PictureLayerImpl> layer =
         PictureLayerImpl::Create(host_impl_->active_tree(), 1, false);
     PictureLayerTilingSet* tiling_set = layer->picture_layer_tiling_set();
+    layer->set_is_drawn_render_surface_layer_list_member(true);
 
     auto* tiling = tiling_set->AddTiling(1.0f, raster);
     tiling->set_resolution(resolutions[i]);
diff --git a/cc/trees/damage_tracker_unittest.cc b/cc/trees/damage_tracker_unittest.cc
index 56d3daf..e8747e2 100644
--- a/cc/trees/damage_tracker_unittest.cc
+++ b/cc/trees/damage_tracker_unittest.cc
@@ -34,10 +34,8 @@
   ASSERT_FALSE(render_surface_layer_list->size());
 
   FakeLayerTreeHostImpl::RecursiveUpdateNumChildren(root);
-  root->layer_tree_impl()->IncrementRenderSurfaceListIdForTesting();
   LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
-      root, root->bounds(), render_surface_layer_list,
-      root->layer_tree_impl()->current_render_surface_list_id());
+      root, root->bounds(), render_surface_layer_list);
   LayerTreeHostCommon::CalculateDrawProperties(&inputs);
   ASSERT_TRUE(root->render_surface());
 }
diff --git a/cc/trees/layer_tree_host_common.cc b/cc/trees/layer_tree_host_common.cc
index eb7c3dd..aef8d33 100644
--- a/cc/trees/layer_tree_host_common.cc
+++ b/cc/trees/layer_tree_host_common.cc
@@ -83,7 +83,6 @@
     bool can_render_to_separate_surface,
     bool can_adjust_raster_scales,
     LayerImplList* render_surface_layer_list,
-    int current_render_surface_layer_list_id,
     PropertyTrees* property_trees)
     : root_layer(root_layer),
       device_viewport_size(device_viewport_size),
@@ -102,16 +101,13 @@
       can_render_to_separate_surface(can_render_to_separate_surface),
       can_adjust_raster_scales(can_adjust_raster_scales),
       render_surface_layer_list(render_surface_layer_list),
-      current_render_surface_layer_list_id(
-          current_render_surface_layer_list_id),
       property_trees(property_trees) {}
 
 LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting::
     CalcDrawPropsImplInputsForTesting(LayerImpl* root_layer,
                                       const gfx::Size& device_viewport_size,
                                       const gfx::Transform& device_transform,
-                                      LayerImplList* render_surface_layer_list,
-                                      int current_render_surface_layer_list_id)
+                                      LayerImplList* render_surface_layer_list)
     : CalcDrawPropsImplInputs(root_layer,
                               device_viewport_size,
                               device_transform,
@@ -128,7 +124,6 @@
                               true,
                               false,
                               render_surface_layer_list,
-                              current_render_surface_layer_list_id,
                               GetPropertyTrees(root_layer)) {
   DCHECK(root_layer);
   DCHECK(render_surface_layer_list);
@@ -137,13 +132,11 @@
 LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting::
     CalcDrawPropsImplInputsForTesting(LayerImpl* root_layer,
                                       const gfx::Size& device_viewport_size,
-                                      LayerImplList* render_surface_layer_list,
-                                      int current_render_surface_layer_list_id)
+                                      LayerImplList* render_surface_layer_list)
     : CalcDrawPropsImplInputsForTesting(root_layer,
                                         device_viewport_size,
                                         gfx::Transform(),
-                                        render_surface_layer_list,
-                                        current_render_surface_layer_list_id) {}
+                                        render_surface_layer_list) {}
 
 bool LayerTreeHostCommon::ScrollUpdateInfo::operator==(
     const LayerTreeHostCommon::ScrollUpdateInfo& other) const {
@@ -209,41 +202,41 @@
          layer->HasPotentiallyRunningTransformAnimation();
 }
 
-static inline void MarkLayerWithRenderSurfaceLayerListId(
-    LayerImpl* layer,
-    int current_render_surface_layer_list_id) {
-  layer->draw_properties().last_drawn_render_surface_layer_list_id =
-      current_render_surface_layer_list_id;
-}
-
-static inline void MarkMasksWithRenderSurfaceLayerListId(
-    LayerImpl* layer,
-    int current_render_surface_layer_list_id) {
-  if (layer->mask_layer()) {
-    MarkLayerWithRenderSurfaceLayerListId(layer->mask_layer(),
-                                          current_render_surface_layer_list_id);
-  }
+static inline void SetMaskLayersAreDrawnRenderSurfaceLayerListMembers(
+    LayerImpl* layer) {
+  if (layer->mask_layer())
+    layer->mask_layer()->set_is_drawn_render_surface_layer_list_member(true);
   if (layer->replica_layer() && layer->replica_layer()->mask_layer()) {
-    MarkLayerWithRenderSurfaceLayerListId(layer->replica_layer()->mask_layer(),
-                                          current_render_surface_layer_list_id);
+    layer->replica_layer()
+        ->mask_layer()
+        ->set_is_drawn_render_surface_layer_list_member(true);
   }
 }
 
-static inline void ClearRenderSurfaceLayerListId(LayerImplList* layer_list,
-                                                 ScrollTree* scroll_tree) {
-  const int cleared_render_surface_layer_list_id = 0;
+static inline void ClearLayerIsDrawnRenderSurfaceLayerListMember(
+    LayerImpl* layer) {
+  layer->set_is_drawn_render_surface_layer_list_member(false);
+  if (layer->mask_layer())
+    layer->mask_layer()->set_is_drawn_render_surface_layer_list_member(false);
+  if (layer->replica_layer() && layer->replica_layer()->mask_layer()) {
+    layer->replica_layer()
+        ->mask_layer()
+        ->set_is_drawn_render_surface_layer_list_member(false);
+  }
+}
+
+static inline void ClearIsDrawnRenderSurfaceLayerListMember(
+    LayerImplList* layer_list,
+    ScrollTree* scroll_tree) {
   for (LayerImpl* layer : *layer_list) {
-    if (layer->IsDrawnRenderSurfaceLayerListMember()) {
+    if (layer->is_drawn_render_surface_layer_list_member()) {
       DCHECK_GT(scroll_tree->Node(layer->scroll_tree_index())
                     ->data.num_drawn_descendants,
                 0);
       scroll_tree->Node(layer->scroll_tree_index())
           ->data.num_drawn_descendants--;
     }
-    MarkLayerWithRenderSurfaceLayerListId(layer,
-                                          cleared_render_surface_layer_list_id);
-    MarkMasksWithRenderSurfaceLayerListId(layer,
-                                          cleared_render_surface_layer_list_id);
+    ClearLayerIsDrawnRenderSurfaceLayerListMember(layer);
   }
 }
 
@@ -478,8 +471,7 @@
     LayerTreeImpl* layer_tree_impl,
     PropertyTrees* property_trees,
     LayerImplList* render_surface_layer_list,
-    bool can_render_to_separate_surface,
-    int current_render_surface_layer_list_id) {
+    bool can_render_to_separate_surface) {
   ScrollTree* scroll_tree = &property_trees->scroll_tree;
   for (int i = 0; i < static_cast<int>(scroll_tree->size()); ++i)
     scroll_tree->Node(i)->data.num_drawn_descendants = 0;
@@ -490,6 +482,7 @@
   for (LayerImpl* layer : *layer_tree_impl) {
     if (layer->render_surface())
       layer->ClearRenderSurfaceLayerList();
+    ClearLayerIsDrawnRenderSurfaceLayerListMember(layer);
 
     bool layer_is_drawn =
         property_trees->effect_tree.Node(layer->effect_tree_index())
@@ -552,8 +545,7 @@
     if (!layer_should_be_drawn)
       continue;
 
-    MarkLayerWithRenderSurfaceLayerListId(layer,
-                                          current_render_surface_layer_list_id);
+    layer->set_is_drawn_render_surface_layer_list_member(true);
     scroll_tree->Node(layer->scroll_tree_index())->data.num_drawn_descendants++;
     layer->render_target()->layer_list().push_back(layer);
 
@@ -586,12 +578,10 @@
   }
 }
 
-static void ComputeListOfNonEmptySurfaces(
-    LayerTreeImpl* layer_tree_impl,
-    PropertyTrees* property_trees,
-    LayerImplList* initial_surface_list,
-    LayerImplList* final_surface_list,
-    int current_render_surface_layer_list_id) {
+static void ComputeListOfNonEmptySurfaces(LayerTreeImpl* layer_tree_impl,
+                                          PropertyTrees* property_trees,
+                                          LayerImplList* initial_surface_list,
+                                          LayerImplList* final_surface_list) {
   // Walk the initial surface list forwards. The root surface and each
   // surface with a non-empty content rect go into the final render surface
   // layer list. Surfaces with empty content rects or whose target isn't in
@@ -602,8 +592,8 @@
     RenderSurfaceImpl* target_surface = surface->render_target();
     if (!is_root && (surface->content_rect().IsEmpty() ||
                      target_surface->layer_list().empty())) {
-      ClearRenderSurfaceLayerListId(&surface->layer_list(),
-                                    &property_trees->scroll_tree);
+      ClearIsDrawnRenderSurfaceLayerListMember(&surface->layer_list(),
+                                               &property_trees->scroll_tree);
       surface->ClearLayerLists();
       if (!is_root) {
         LayerImplList& target_list = target_surface->layer_list();
@@ -624,8 +614,7 @@
       }
       continue;
     }
-    MarkMasksWithRenderSurfaceLayerListId(layer,
-                                          current_render_surface_layer_list_id);
+    SetMaskLayersAreDrawnRenderSurfaceLayerListMembers(layer);
     final_surface_list->push_back(layer);
   }
 }
@@ -635,7 +624,6 @@
     PropertyTrees* property_trees,
     LayerImplList* render_surface_layer_list,
     const bool can_render_to_separate_surface,
-    const int current_render_surface_layer_list_id,
     const int max_texture_size) {
   // This calculates top level Render Surface Layer List, and Layer List for all
   // Render Surfaces.
@@ -646,14 +634,14 @@
   // First compute an RSLL that might include surfaces that later turn out to
   // have an empty content rect. After surface content rects are computed,
   // produce a final RSLL that omits empty surfaces.
-  ComputeInitialRenderSurfaceLayerList(
-      layer_tree_impl, property_trees, &initial_render_surface_list,
-      can_render_to_separate_surface, current_render_surface_layer_list_id);
+  ComputeInitialRenderSurfaceLayerList(layer_tree_impl, property_trees,
+                                       &initial_render_surface_list,
+                                       can_render_to_separate_surface);
   ComputeSurfaceContentRects(layer_tree_impl, property_trees,
                              &initial_render_surface_list, max_texture_size);
-  ComputeListOfNonEmptySurfaces(
-      layer_tree_impl, property_trees, &initial_render_surface_list,
-      render_surface_layer_list, current_render_surface_layer_list_id);
+  ComputeListOfNonEmptySurfaces(layer_tree_impl, property_trees,
+                                &initial_render_surface_list,
+                                render_surface_layer_list);
 
   ComputeLayerScrollsDrawnDescendants(layer_tree_impl,
                                       &property_trees->scroll_tree);
@@ -767,13 +755,10 @@
       ComputeMaskLayerDrawProperties(layer, replica_mask_layer);
   }
 
-  DCHECK_EQ(
-      inputs->current_render_surface_layer_list_id,
-      inputs->root_layer->layer_tree_impl()->current_render_surface_list_id());
   CalculateRenderSurfaceLayerList(
       inputs->root_layer->layer_tree_impl(), inputs->property_trees,
       inputs->render_surface_layer_list, inputs->can_render_to_separate_surface,
-      inputs->current_render_surface_layer_list_id, inputs->max_texture_size);
+      inputs->max_texture_size);
 
   if (should_measure_property_tree_performance) {
     TRACE_EVENT_END0(TRACE_DISABLED_BY_DEFAULT("cc.debug.cdp-perf"),
diff --git a/cc/trees/layer_tree_host_common.h b/cc/trees/layer_tree_host_common.h
index 5f2d720b..10c0a1a 100644
--- a/cc/trees/layer_tree_host_common.h
+++ b/cc/trees/layer_tree_host_common.h
@@ -82,7 +82,6 @@
         bool can_render_to_separate_surface,
         bool can_adjust_raster_scales,
         LayerImplList* render_surface_layer_list,
-        int current_render_surface_layer_list_id,
         PropertyTrees* property_trees);
 
     LayerImpl* root_layer;
@@ -101,7 +100,6 @@
     bool can_render_to_separate_surface;
     bool can_adjust_raster_scales;
     LayerImplList* render_surface_layer_list;
-    int current_render_surface_layer_list_id;
     PropertyTrees* property_trees;
   };
 
@@ -110,12 +108,10 @@
     CalcDrawPropsImplInputsForTesting(LayerImpl* root_layer,
                                       const gfx::Size& device_viewport_size,
                                       const gfx::Transform& device_transform,
-                                      LayerImplList* render_surface_layer_list,
-                                      int current_render_surface_layer_list_id);
+                                      LayerImplList* render_surface_layer_list);
     CalcDrawPropsImplInputsForTesting(LayerImpl* root_layer,
                                       const gfx::Size& device_viewport_size,
-                                      LayerImplList* render_surface_layer_list,
-                                      int current_render_surface_layer_list_id);
+                                      LayerImplList* render_surface_layer_list);
   };
 
   static int CalculateLayerJitter(LayerImpl* scrolling_layer);
diff --git a/cc/trees/layer_tree_host_common_perftest.cc b/cc/trees/layer_tree_host_common_perftest.cc
index 260e5743..30b0cbc 100644
--- a/cc/trees/layer_tree_host_common_perftest.cc
+++ b/cc/trees/layer_tree_host_common_perftest.cc
@@ -107,7 +107,6 @@
                                 LayerTreeImpl* active_tree,
                                 LayerTreeHostImpl* host_impl) {
     LayerImplList update_list;
-    active_tree->IncrementRenderSurfaceListIdForTesting();
     LayerTreeHostCommon::CalcDrawPropsImplInputs inputs(
         active_tree->root_layer(), active_tree->DrawViewportSize(),
         host_impl->DrawTransform(), active_tree->device_scale_factor(),
@@ -121,8 +120,7 @@
         host_impl->settings().layers_always_allowed_lcd_text,
         can_render_to_separate_surface,
         host_impl->settings().layer_transforms_should_scale_layer_contents,
-        &update_list, active_tree->current_render_surface_list_id(),
-        active_tree->property_trees());
+        &update_list, active_tree->property_trees());
     LayerTreeHostCommon::CalculateDrawProperties(&inputs);
   }
 };
diff --git a/cc/trees/layer_tree_host_common_unittest.cc b/cc/trees/layer_tree_host_common_unittest.cc
index 660a7ffc..99dca32 100644
--- a/cc/trees/layer_tree_host_common_unittest.cc
+++ b/cc/trees/layer_tree_host_common_unittest.cc
@@ -1108,10 +1108,8 @@
   // render_surface will have a sublayer scale because of device scale factor.
   float device_scale_factor = 2.0f;
   LayerImplList render_surface_layer_list_impl;
-  root->layer_tree_impl()->IncrementRenderSurfaceListIdForTesting();
   LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
-      root, root->bounds(), translate, &render_surface_layer_list_impl,
-      root->layer_tree_impl()->current_render_surface_list_id());
+      root, root->bounds(), translate, &render_surface_layer_list_impl);
   inputs.device_scale_factor = device_scale_factor;
   inputs.property_trees->needs_rebuild = true;
   LayerTreeHostCommon::CalculateDrawProperties(&inputs);
@@ -1145,10 +1143,8 @@
   translate.Translate(50, 50);
   {
     LayerImplList render_surface_layer_list_impl;
-    root->layer_tree_impl()->IncrementRenderSurfaceListIdForTesting();
     LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
-        root, root->bounds(), translate, &render_surface_layer_list_impl,
-        root->layer_tree_impl()->current_render_surface_list_id());
+        root, root->bounds(), translate, &render_surface_layer_list_impl);
     inputs.property_trees->needs_rebuild = true;
     LayerTreeHostCommon::CalculateDrawProperties(&inputs);
     EXPECT_EQ(translate, root->draw_properties().target_space_transform);
@@ -1160,10 +1156,8 @@
   scale.Scale(2, 2);
   {
     LayerImplList render_surface_layer_list_impl;
-    root->layer_tree_impl()->IncrementRenderSurfaceListIdForTesting();
     LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
-        root, root->bounds(), scale, &render_surface_layer_list_impl,
-        root->layer_tree_impl()->current_render_surface_list_id());
+        root, root->bounds(), scale, &render_surface_layer_list_impl);
     inputs.property_trees->needs_rebuild = true;
     LayerTreeHostCommon::CalculateDrawProperties(&inputs);
     EXPECT_EQ(scale, root->draw_properties().target_space_transform);
@@ -1175,10 +1169,8 @@
   rotate.Rotate(2);
   {
     LayerImplList render_surface_layer_list_impl;
-    root->layer_tree_impl()->IncrementRenderSurfaceListIdForTesting();
     LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
-        root, root->bounds(), rotate, &render_surface_layer_list_impl,
-        root->layer_tree_impl()->current_render_surface_list_id());
+        root, root->bounds(), rotate, &render_surface_layer_list_impl);
     inputs.property_trees->needs_rebuild = true;
     LayerTreeHostCommon::CalculateDrawProperties(&inputs);
     EXPECT_EQ(rotate, root->draw_properties().target_space_transform);
@@ -1192,10 +1184,8 @@
   composite.ConcatTransform(rotate);
   {
     LayerImplList render_surface_layer_list_impl;
-    root->layer_tree_impl()->IncrementRenderSurfaceListIdForTesting();
     LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
-        root, root->bounds(), composite, &render_surface_layer_list_impl,
-        root->layer_tree_impl()->current_render_surface_list_id());
+        root, root->bounds(), composite, &render_surface_layer_list_impl);
     inputs.property_trees->needs_rebuild = true;
     LayerTreeHostCommon::CalculateDrawProperties(&inputs);
     EXPECT_EQ(composite, root->draw_properties().target_space_transform);
@@ -1208,10 +1198,8 @@
 
   {
     LayerImplList render_surface_layer_list_impl;
-    root->layer_tree_impl()->IncrementRenderSurfaceListIdForTesting();
     LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
-        root, root->bounds(), translate, &render_surface_layer_list_impl,
-        root->layer_tree_impl()->current_render_surface_list_id());
+        root, root->bounds(), translate, &render_surface_layer_list_impl);
     inputs.device_scale_factor = device_scale_factor;
     inputs.property_trees->needs_rebuild = true;
     LayerTreeHostCommon::CalculateDrawProperties(&inputs);
@@ -1229,10 +1217,8 @@
 
   {
     LayerImplList render_surface_layer_list_impl;
-    root->layer_tree_impl()->IncrementRenderSurfaceListIdForTesting();
     LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
-        root, root->bounds(), translate, &render_surface_layer_list_impl,
-        root->layer_tree_impl()->current_render_surface_list_id());
+        root, root->bounds(), translate, &render_surface_layer_list_impl);
     inputs.page_scale_factor = page_scale_factor;
     inputs.page_scale_layer = root;
     inputs.property_trees->needs_rebuild = true;
@@ -1251,10 +1237,8 @@
 
   {
     LayerImplList render_surface_layer_list_impl;
-    root->layer_tree_impl()->IncrementRenderSurfaceListIdForTesting();
     LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
-        root, root->bounds(), composite, &render_surface_layer_list_impl,
-        root->layer_tree_impl()->current_render_surface_list_id());
+        root, root->bounds(), composite, &render_surface_layer_list_impl);
     inputs.property_trees->needs_rebuild = true;
     LayerTreeHostCommon::CalculateDrawProperties(&inputs);
     gfx::Transform compositeSquared = composite;
@@ -1313,10 +1297,8 @@
   render_surface1->SetOpacity(0.f);
 
   LayerImplList render_surface_layer_list;
-  parent->layer_tree_impl()->IncrementRenderSurfaceListIdForTesting();
   LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
-      parent, parent->bounds(), &render_surface_layer_list,
-      parent->layer_tree_impl()->current_render_surface_list_id());
+      parent, parent->bounds(), &render_surface_layer_list);
   inputs.can_adjust_raster_scales = true;
   LayerTreeHostCommon::CalculateDrawProperties(&inputs);
 
@@ -1356,10 +1338,8 @@
 
   {
     LayerImplList render_surface_layer_list;
-    parent->layer_tree_impl()->IncrementRenderSurfaceListIdForTesting();
     LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
-        parent, parent->bounds(), &render_surface_layer_list,
-        parent->layer_tree_impl()->current_render_surface_list_id());
+        parent, parent->bounds(), &render_surface_layer_list);
     inputs.can_adjust_raster_scales = true;
     LayerTreeHostCommon::CalculateDrawProperties(&inputs);
     EXPECT_EQ(2U, render_surface_layer_list.size());
@@ -1381,10 +1361,8 @@
   render_surface1->set_visible_layer_rect(gfx::Rect());
   {
     LayerImplList render_surface_layer_list;
-    parent->layer_tree_impl()->IncrementRenderSurfaceListIdForTesting();
     LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
-        parent, parent->bounds(), &render_surface_layer_list,
-        parent->layer_tree_impl()->current_render_surface_list_id());
+        parent, parent->bounds(), &render_surface_layer_list);
     inputs.can_adjust_raster_scales = true;
     LayerTreeHostCommon::CalculateDrawProperties(&inputs);
   }
@@ -1421,10 +1399,8 @@
   parent->SetFilters(filters);
 
   LayerImplList render_surface_layer_list;
-  parent->layer_tree_impl()->IncrementRenderSurfaceListIdForTesting();
   LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
-      root, root->bounds(), &render_surface_layer_list,
-      root->layer_tree_impl()->current_render_surface_list_id());
+      root, root->bounds(), &render_surface_layer_list);
   inputs.can_adjust_raster_scales = true;
   LayerTreeHostCommon::CalculateDrawProperties(&inputs);
 
@@ -3458,11 +3434,9 @@
                                true, false, false);
 
   LayerImplList render_surface_layer_list_impl;
-  root->layer_tree_impl()->IncrementRenderSurfaceListIdForTesting();
   // Now set the root render surface an empty clip.
   LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
-      root, gfx::Size(), &render_surface_layer_list_impl,
-      root->layer_tree_impl()->current_render_surface_list_id());
+      root, gfx::Size(), &render_surface_layer_list_impl);
 
   LayerTreeHostCommon::CalculateDrawProperties(&inputs);
   ASSERT_TRUE(root->render_surface());
@@ -5224,10 +5198,8 @@
   host_impl.pending_tree()->SetRootLayer(std::move(root));
 
   LayerImplList render_surface_layer_list;
-  root_layer->layer_tree_impl()->IncrementRenderSurfaceListIdForTesting();
   LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
-      root_layer, root_layer->bounds(), &render_surface_layer_list,
-      root_layer->layer_tree_impl()->current_render_surface_list_id());
+      root_layer, root_layer->bounds(), &render_surface_layer_list);
   inputs.can_adjust_raster_scales = true;
   LayerTreeHostCommon::CalculateDrawProperties(&inputs);
 
@@ -5241,10 +5213,8 @@
   root_layer->SetOpacity(0.0f);
   root_layer->layer_tree_impl()->property_trees()->needs_rebuild = true;
   LayerImplList render_surface_layer_list2;
-  root_layer->layer_tree_impl()->IncrementRenderSurfaceListIdForTesting();
   LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs2(
-      root_layer, root_layer->bounds(), &render_surface_layer_list2,
-      root_layer->layer_tree_impl()->current_render_surface_list_id());
+      root_layer, root_layer->bounds(), &render_surface_layer_list2);
   inputs2.can_adjust_raster_scales = true;
   LayerTreeHostCommon::CalculateDrawProperties(&inputs2);
 
@@ -5260,10 +5230,8 @@
   child_ptr->SetOpacity(0.0f);
   root_layer->layer_tree_impl()->property_trees()->needs_rebuild = true;
   LayerImplList render_surface_layer_list3;
-  root_layer->layer_tree_impl()->IncrementRenderSurfaceListIdForTesting();
   LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs3(
-      root_layer, root_layer->bounds(), &render_surface_layer_list3,
-      root_layer->layer_tree_impl()->current_render_surface_list_id());
+      root_layer, root_layer->bounds(), &render_surface_layer_list3);
   inputs3.can_adjust_raster_scales = true;
   LayerTreeHostCommon::CalculateDrawProperties(&inputs3);
 
@@ -5560,10 +5528,8 @@
   host_impl.pending_tree()->SetRootLayer(std::move(root));
 
   LayerImplList render_surface_layer_list;
-  root_layer->layer_tree_impl()->IncrementRenderSurfaceListIdForTesting();
   LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
-      root_layer, root_layer->bounds(), &render_surface_layer_list,
-      root_layer->layer_tree_impl()->current_render_surface_list_id());
+      root_layer, root_layer->bounds(), &render_surface_layer_list);
   inputs.can_adjust_raster_scales = true;
   LayerTreeHostCommon::CalculateDrawProperties(&inputs);
 
@@ -5612,10 +5578,8 @@
   host_impl.pending_tree()->SetRootLayer(std::move(root));
 
   LayerImplList render_surface_layer_list;
-  root_layer->layer_tree_impl()->IncrementRenderSurfaceListIdForTesting();
   LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
-      root_layer, root_layer->bounds(), &render_surface_layer_list,
-      root_layer->layer_tree_impl()->current_render_surface_list_id());
+      root_layer, root_layer->bounds(), &render_surface_layer_list);
   inputs.can_adjust_raster_scales = true;
   LayerTreeHostCommon::CalculateDrawProperties(&inputs);
 
@@ -5727,10 +5691,8 @@
   EXPECT_TRUE(copy_layer->HasCopyRequest());
 
   LayerImplList render_surface_layer_list;
-  root_layer->layer_tree_impl()->IncrementRenderSurfaceListIdForTesting();
   LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
-      root_layer, root_layer->bounds(), &render_surface_layer_list,
-      root_layer->layer_tree_impl()->current_render_surface_list_id());
+      root_layer, root_layer->bounds(), &render_surface_layer_list);
   inputs.can_adjust_raster_scales = true;
   LayerTreeHostCommon::CalculateDrawProperties(&inputs);
 
@@ -5840,12 +5802,10 @@
   root->AddChild(std::move(copy_parent));
 
   LayerImplList render_surface_layer_list;
-  root->layer_tree_impl()->IncrementRenderSurfaceListIdForTesting();
   LayerImpl* root_layer = root.get();
   root_layer->layer_tree_impl()->SetRootLayer(std::move(root));
   LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
-      root_layer, root_layer->bounds(), &render_surface_layer_list,
-      root_layer->layer_tree_impl()->current_render_surface_list_id());
+      root_layer, root_layer->bounds(), &render_surface_layer_list);
   inputs.can_adjust_raster_scales = true;
   LayerTreeHostCommon::CalculateDrawProperties(&inputs);
 
@@ -6366,10 +6326,8 @@
   {
     LayerImplList render_surface_layer_list;
     FakeLayerTreeHostImpl::RecursiveUpdateNumChildren(root_layer);
-    root_layer->layer_tree_impl()->IncrementRenderSurfaceListIdForTesting();
     LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
-        root_layer, root_layer->bounds(), &render_surface_layer_list,
-        root_layer->layer_tree_impl()->current_render_surface_list_id());
+        root_layer, root_layer->bounds(), &render_surface_layer_list);
     inputs.can_render_to_separate_surface = true;
     LayerTreeHostCommon::CalculateDrawProperties(&inputs);
 
@@ -6399,10 +6357,8 @@
 
   {
     LayerImplList render_surface_layer_list;
-    root_layer->layer_tree_impl()->IncrementRenderSurfaceListIdForTesting();
     LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
-        root_layer, root_layer->bounds(), &render_surface_layer_list,
-        root_layer->layer_tree_impl()->current_render_surface_list_id());
+        root_layer, root_layer->bounds(), &render_surface_layer_list);
     inputs.can_render_to_separate_surface = false;
     LayerTreeHostCommon::CalculateDrawProperties(&inputs);
 
@@ -6690,10 +6646,9 @@
 
   float device_scale_factor = 1.5f;
   LayerImplList render_surface_layer_list_impl;
-  root->layer_tree_impl()->IncrementRenderSurfaceListIdForTesting();
   LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
-      root, root->bounds(), identity_transform, &render_surface_layer_list_impl,
-      root->layer_tree_impl()->current_render_surface_list_id());
+      root, root->bounds(), identity_transform,
+      &render_surface_layer_list_impl);
   inputs.device_scale_factor = device_scale_factor;
   LayerTreeHostCommon::CalculateDrawProperties(&inputs);
 
@@ -7125,10 +7080,8 @@
     SetScrollOffsetDelta(scroll_layer, scroll_delta);
 
     LayerImplList render_surface_layer_list;
-    root->layer_tree_impl()->IncrementRenderSurfaceListIdForTesting();
     LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
-        root, root->bounds(), &render_surface_layer_list,
-        root->layer_tree_impl()->current_render_surface_list_id());
+        root, root->bounds(), &render_surface_layer_list);
     root->layer_tree_impl()
         ->property_trees()
         ->transform_tree.set_source_to_parent_updates_allowed(false);
@@ -7155,10 +7108,8 @@
     gfx::Vector2dF rounded_scroll_delta(4.f, 8.f);
 
     LayerImplList render_surface_layer_list;
-    root->layer_tree_impl()->IncrementRenderSurfaceListIdForTesting();
     LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
-        root, root->bounds(), &render_surface_layer_list,
-        root->layer_tree_impl()->current_render_surface_list_id());
+        root, root->bounds(), &render_surface_layer_list);
     LayerTreeHostCommon::CalculateDrawProperties(&inputs);
 
     EXPECT_TRANSFORMATION_MATRIX_EQ(
@@ -7185,10 +7136,8 @@
     SetScrollOffsetDelta(scroll_layer, scroll_delta);
 
     LayerImplList render_surface_layer_list;
-    root->layer_tree_impl()->IncrementRenderSurfaceListIdForTesting();
     LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
-        root, root->bounds(), &render_surface_layer_list,
-        root->layer_tree_impl()->current_render_surface_list_id());
+        root, root->bounds(), &render_surface_layer_list);
     LayerTreeHostCommon::CalculateDrawProperties(&inputs);
 
     EXPECT_TRANSFORMATION_MATRIX_EQ(
@@ -7612,10 +7561,6 @@
       grand_child_raw->draw_properties().starting_animation_contents_scale);
 }
 
-static int membership_id(LayerImpl* layer) {
-  return layer->draw_properties().last_drawn_render_surface_layer_list_id;
-}
-
 static void GatherDrawnLayers(LayerImplList* rsll,
                               std::set<LayerImpl*>* drawn_layers) {
   for (LayerIterator it = LayerIterator::Begin(rsll),
@@ -7687,13 +7632,12 @@
 
   // Start with nothing being drawn.
   ExecuteCalculateDrawProperties(grand_parent_raw);
-  int member_id = render_surface_layer_list_count();
 
-  EXPECT_NE(member_id, membership_id(grand_parent_raw));
-  EXPECT_NE(member_id, membership_id(parent_raw));
-  EXPECT_NE(member_id, membership_id(child_raw));
-  EXPECT_NE(member_id, membership_id(grand_child1_raw));
-  EXPECT_NE(member_id, membership_id(grand_child2_raw));
+  EXPECT_FALSE(grand_parent_raw->is_drawn_render_surface_layer_list_member());
+  EXPECT_FALSE(parent_raw->is_drawn_render_surface_layer_list_member());
+  EXPECT_FALSE(child_raw->is_drawn_render_surface_layer_list_member());
+  EXPECT_FALSE(grand_child1_raw->is_drawn_render_surface_layer_list_member());
+  EXPECT_FALSE(grand_child2_raw->is_drawn_render_surface_layer_list_member());
 
   std::set<LayerImpl*> expected;
   std::set<LayerImpl*> actual;
@@ -7706,13 +7650,12 @@
   grand_child1_raw->layer_tree_impl()->property_trees()->needs_rebuild = true;
 
   ExecuteCalculateDrawProperties(grand_parent_raw);
-  member_id = render_surface_layer_list_count();
 
-  EXPECT_NE(member_id, membership_id(grand_parent_raw));
-  EXPECT_NE(member_id, membership_id(parent_raw));
-  EXPECT_NE(member_id, membership_id(child_raw));
-  EXPECT_NE(member_id, membership_id(grand_child1_raw));
-  EXPECT_NE(member_id, membership_id(grand_child2_raw));
+  EXPECT_FALSE(grand_parent_raw->is_drawn_render_surface_layer_list_member());
+  EXPECT_FALSE(parent_raw->is_drawn_render_surface_layer_list_member());
+  EXPECT_FALSE(child_raw->is_drawn_render_surface_layer_list_member());
+  EXPECT_FALSE(grand_child1_raw->is_drawn_render_surface_layer_list_member());
+  EXPECT_FALSE(grand_child2_raw->is_drawn_render_surface_layer_list_member());
 
   expected.clear();
   actual.clear();
@@ -7724,13 +7667,12 @@
   grand_child1_raw->SetDrawsContent(true);
 
   ExecuteCalculateDrawProperties(grand_parent_raw);
-  member_id = render_surface_layer_list_count();
 
-  EXPECT_NE(member_id, membership_id(grand_parent_raw));
-  EXPECT_NE(member_id, membership_id(parent_raw));
-  EXPECT_NE(member_id, membership_id(child_raw));
-  EXPECT_EQ(member_id, membership_id(grand_child1_raw));
-  EXPECT_NE(member_id, membership_id(grand_child2_raw));
+  EXPECT_FALSE(grand_parent_raw->is_drawn_render_surface_layer_list_member());
+  EXPECT_FALSE(parent_raw->is_drawn_render_surface_layer_list_member());
+  EXPECT_FALSE(child_raw->is_drawn_render_surface_layer_list_member());
+  EXPECT_TRUE(grand_child1_raw->is_drawn_render_surface_layer_list_member());
+  EXPECT_FALSE(grand_child2_raw->is_drawn_render_surface_layer_list_member());
 
   expected.clear();
   expected.insert(grand_child1_raw);
@@ -7748,13 +7690,12 @@
   grand_child2_raw->SetDrawsContent(true);
 
   ExecuteCalculateDrawProperties(grand_parent_raw);
-  member_id = render_surface_layer_list_count();
 
-  EXPECT_NE(member_id, membership_id(grand_parent_raw));
-  EXPECT_NE(member_id, membership_id(parent_raw));
-  EXPECT_NE(member_id, membership_id(child_raw));
-  EXPECT_NE(member_id, membership_id(grand_child1_raw));
-  EXPECT_EQ(member_id, membership_id(grand_child2_raw));
+  EXPECT_FALSE(grand_parent_raw->is_drawn_render_surface_layer_list_member());
+  EXPECT_FALSE(parent_raw->is_drawn_render_surface_layer_list_member());
+  EXPECT_FALSE(child_raw->is_drawn_render_surface_layer_list_member());
+  EXPECT_FALSE(grand_child1_raw->is_drawn_render_surface_layer_list_member());
+  EXPECT_TRUE(grand_child2_raw->is_drawn_render_surface_layer_list_member());
 
   expected.clear();
   expected.insert(grand_child2_raw);
@@ -7768,14 +7709,14 @@
   child_raw->layer_tree_impl()->property_trees()->needs_rebuild = true;
 
   ExecuteCalculateDrawProperties(grand_parent_raw);
-  member_id = render_surface_layer_list_count();
 
-  EXPECT_NE(member_id, membership_id(grand_parent_raw));
-  EXPECT_NE(member_id, membership_id(parent_raw));
-  EXPECT_NE(member_id, membership_id(child_raw));
-  EXPECT_EQ(member_id, membership_id(child_raw->mask_layer()));
-  EXPECT_NE(member_id, membership_id(grand_child1_raw));
-  EXPECT_EQ(member_id, membership_id(grand_child2_raw));
+  EXPECT_FALSE(grand_parent_raw->is_drawn_render_surface_layer_list_member());
+  EXPECT_FALSE(parent_raw->is_drawn_render_surface_layer_list_member());
+  EXPECT_FALSE(child_raw->is_drawn_render_surface_layer_list_member());
+  EXPECT_TRUE(
+      child_raw->mask_layer()->is_drawn_render_surface_layer_list_member());
+  EXPECT_FALSE(grand_child1_raw->is_drawn_render_surface_layer_list_member());
+  EXPECT_TRUE(grand_child2_raw->is_drawn_render_surface_layer_list_member());
 
   expected.clear();
   expected.insert(grand_child2_raw);
@@ -7797,15 +7738,17 @@
   child_raw->layer_tree_impl()->property_trees()->needs_rebuild = true;
 
   ExecuteCalculateDrawProperties(grand_parent_raw);
-  member_id = render_surface_layer_list_count();
 
-  EXPECT_NE(member_id, membership_id(grand_parent_raw));
-  EXPECT_NE(member_id, membership_id(parent_raw));
-  EXPECT_NE(member_id, membership_id(child_raw));
-  EXPECT_EQ(member_id, membership_id(child_raw->mask_layer()));
-  EXPECT_EQ(member_id, membership_id(child_raw->replica_layer()->mask_layer()));
-  EXPECT_NE(member_id, membership_id(grand_child1_raw));
-  EXPECT_EQ(member_id, membership_id(grand_child2_raw));
+  EXPECT_FALSE(grand_parent_raw->is_drawn_render_surface_layer_list_member());
+  EXPECT_FALSE(parent_raw->is_drawn_render_surface_layer_list_member());
+  EXPECT_FALSE(child_raw->is_drawn_render_surface_layer_list_member());
+  EXPECT_TRUE(
+      child_raw->mask_layer()->is_drawn_render_surface_layer_list_member());
+  EXPECT_TRUE(child_raw->replica_layer()
+                  ->mask_layer()
+                  ->is_drawn_render_surface_layer_list_member());
+  EXPECT_FALSE(grand_child1_raw->is_drawn_render_surface_layer_list_member());
+  EXPECT_TRUE(grand_child2_raw->is_drawn_render_surface_layer_list_member());
 
   expected.clear();
   expected.insert(grand_child2_raw);
@@ -7822,14 +7765,14 @@
   grand_child2_raw->SetDrawsContent(false);
 
   ExecuteCalculateDrawProperties(grand_parent_raw);
-  member_id = render_surface_layer_list_count();
 
-  EXPECT_NE(member_id, membership_id(grand_parent_raw));
-  EXPECT_NE(member_id, membership_id(parent_raw));
-  EXPECT_NE(member_id, membership_id(child_raw));
-  EXPECT_NE(member_id, membership_id(child_raw->mask_layer()));
-  EXPECT_NE(member_id, membership_id(grand_child1_raw));
-  EXPECT_NE(member_id, membership_id(grand_child2_raw));
+  EXPECT_FALSE(grand_parent_raw->is_drawn_render_surface_layer_list_member());
+  EXPECT_FALSE(parent_raw->is_drawn_render_surface_layer_list_member());
+  EXPECT_FALSE(child_raw->is_drawn_render_surface_layer_list_member());
+  EXPECT_FALSE(
+      child_raw->mask_layer()->is_drawn_render_surface_layer_list_member());
+  EXPECT_FALSE(grand_child1_raw->is_drawn_render_surface_layer_list_member());
+  EXPECT_FALSE(grand_child2_raw->is_drawn_render_surface_layer_list_member());
 
   expected.clear();
   actual.clear();
@@ -7841,14 +7784,14 @@
   child_raw->SetDrawsContent(true);
 
   ExecuteCalculateDrawProperties(grand_parent_raw);
-  member_id = render_surface_layer_list_count();
 
-  EXPECT_NE(member_id, membership_id(grand_parent_raw));
-  EXPECT_NE(member_id, membership_id(parent_raw));
-  EXPECT_EQ(member_id, membership_id(child_raw));
-  EXPECT_EQ(member_id, membership_id(child_raw->mask_layer()));
-  EXPECT_NE(member_id, membership_id(grand_child1_raw));
-  EXPECT_NE(member_id, membership_id(grand_child2_raw));
+  EXPECT_FALSE(grand_parent_raw->is_drawn_render_surface_layer_list_member());
+  EXPECT_FALSE(parent_raw->is_drawn_render_surface_layer_list_member());
+  EXPECT_TRUE(child_raw->is_drawn_render_surface_layer_list_member());
+  EXPECT_TRUE(
+      child_raw->mask_layer()->is_drawn_render_surface_layer_list_member());
+  EXPECT_FALSE(grand_child1_raw->is_drawn_render_surface_layer_list_member());
+  EXPECT_FALSE(grand_child2_raw->is_drawn_render_surface_layer_list_member());
 
   expected.clear();
   expected.insert(child_raw);
@@ -7868,13 +7811,12 @@
   grand_child2_raw->SetDrawsContent(true);
 
   ExecuteCalculateDrawProperties(grand_parent_raw);
-  member_id = render_surface_layer_list_count();
 
-  EXPECT_EQ(member_id, membership_id(grand_parent_raw));
-  EXPECT_EQ(member_id, membership_id(parent_raw));
-  EXPECT_EQ(member_id, membership_id(child_raw));
-  EXPECT_EQ(member_id, membership_id(grand_child1_raw));
-  EXPECT_EQ(member_id, membership_id(grand_child2_raw));
+  EXPECT_TRUE(grand_parent_raw->is_drawn_render_surface_layer_list_member());
+  EXPECT_TRUE(parent_raw->is_drawn_render_surface_layer_list_member());
+  EXPECT_TRUE(child_raw->is_drawn_render_surface_layer_list_member());
+  EXPECT_TRUE(grand_child1_raw->is_drawn_render_surface_layer_list_member());
+  EXPECT_TRUE(grand_child2_raw->is_drawn_render_surface_layer_list_member());
 
   expected.clear();
   expected.insert(grand_parent_raw);
@@ -7984,10 +7926,8 @@
   gfx::Size device_viewport_size =
       gfx::Size(root_layer->bounds().width() * device_scale_factor,
                 root_layer->bounds().height() * device_scale_factor);
-  root_layer->layer_tree_impl()->IncrementRenderSurfaceListIdForTesting();
   LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
-      root_layer, device_viewport_size, &render_surface_layer_list,
-      root_layer->layer_tree_impl()->current_render_surface_list_id());
+      root_layer, device_viewport_size, &render_surface_layer_list);
 
   inputs.page_scale_factor = page_scale_factor;
   inputs.can_adjust_raster_scales = true;
@@ -8073,11 +8013,9 @@
 
   gfx::Size device_viewport_size(768, 582);
   LayerImplList render_surface_layer_list_impl;
-  root->layer_tree_impl()->IncrementRenderSurfaceListIdForTesting();
   LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
       root, device_viewport_size, identity_matrix,
-      &render_surface_layer_list_impl,
-      root->layer_tree_impl()->current_render_surface_list_id());
+      &render_surface_layer_list_impl);
   inputs.device_scale_factor = 2.f;
   inputs.page_scale_factor = 1.f;
   inputs.page_scale_layer = NULL;
@@ -8140,10 +8078,8 @@
   sublayer->SetDrawsContent(true);
 
   LayerImplList layer_impl_list;
-  root->layer_tree_impl()->IncrementRenderSurfaceListIdForTesting();
   LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
-      root, device_viewport_size, &layer_impl_list,
-      root->layer_tree_impl()->current_render_surface_list_id());
+      root, device_viewport_size, &layer_impl_list);
 
   LayerTreeHostCommon::CalculateDrawProperties(&inputs);
   EXPECT_EQ(gfx::Rect(root_size), sublayer->visible_layer_rect());
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 25822a64..06f81fe 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -1433,7 +1433,7 @@
   // CommitComplete below.
   LayerImplList list;
   LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
-      root, gfx::Size(50, 50), &list, 0);
+      root, gfx::Size(50, 50), &list);
   LayerTreeHostCommon::CalculateDrawProperties(&inputs);
 
   EXPECT_FALSE(did_request_next_frame_);
diff --git a/cc/trees/layer_tree_host_unittest_animation.cc b/cc/trees/layer_tree_host_unittest_animation.cc
index bc9f6b8d..22a3d55 100644
--- a/cc/trees/layer_tree_host_unittest_animation.cc
+++ b/cc/trees/layer_tree_host_unittest_animation.cc
@@ -753,6 +753,63 @@
 SINGLE_AND_MULTI_THREAD_TEST_F(
     LayerTreeHostAnimationTestScrollOffsetChangesArePropagated);
 
+// Verifies that when a main thread scrolling reason gets added, the
+// notification to takover the animation on the main thread gets sent.
+class LayerTreeHostAnimationTestScrollOffsetAnimationTakeover
+    : public LayerTreeHostAnimationTest {
+ public:
+  LayerTreeHostAnimationTestScrollOffsetAnimationTakeover() {}
+
+  void SetupTree() override {
+    LayerTreeHostAnimationTest::SetupTree();
+
+    scroll_layer_ = FakePictureLayer::Create(&client_);
+    scroll_layer_->SetBounds(gfx::Size(10000, 10000));
+    client_.set_bounds(scroll_layer_->bounds());
+    scroll_layer_->SetScrollOffset(gfx::ScrollOffset(10, 20));
+    layer_tree_host()->root_layer()->AddChild(scroll_layer_);
+
+    AttachPlayersToTimeline();
+    player_child_->AttachElement(scroll_layer_->id());
+    // Allows NotifyAnimationTakeover to get called.
+    player_child_->set_animation_delegate(this);
+  }
+
+  void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+  void DidCommit() override {
+    // Add a main thread scrolling reason after the first commit to trigger
+    // the takeover path.
+    if (layer_tree_host()->source_frame_number() == 1) {
+      scroll_layer_->AddMainThreadScrollingReasons(
+          MainThreadScrollingReason::kHasNonLayerViewportConstrainedObjects);
+    }
+  }
+
+  void WillCommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
+    if (host_impl->sync_tree()->source_frame_number() == 0) {
+      host_impl->animation_host()->ImplOnlyScrollAnimationCreate(
+          scroll_layer_->id(), gfx::ScrollOffset(650.f, 750.f),
+          gfx::ScrollOffset(10, 20));
+    }
+  }
+
+  void NotifyAnimationTakeover(base::TimeTicks monotonic_time,
+                               TargetProperty::Type target_property,
+                               double animation_start_time,
+                               std::unique_ptr<AnimationCurve> curve) override {
+    EndTest();
+  }
+
+  void AfterTest() override {}
+
+ private:
+  FakeContentLayerClient client_;
+  scoped_refptr<FakePictureLayer> scroll_layer_;
+};
+
+MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestScrollOffsetAnimationTakeover);
+
 // Verifies that when the main thread removes a scroll animation and sets a new
 // scroll position, the active tree takes on exactly this new scroll position
 // after activation, and the main thread doesn't receive a spurious scroll
diff --git a/cc/trees/layer_tree_host_unittest_occlusion.cc b/cc/trees/layer_tree_host_unittest_occlusion.cc
index eed7a0b..1d3b3963 100644
--- a/cc/trees/layer_tree_host_unittest_occlusion.cc
+++ b/cc/trees/layer_tree_host_unittest_occlusion.cc
@@ -52,8 +52,8 @@
     LayerImpl* child = impl->active_tree()->LayerById(child_->id());
 
     // Verify the draw properties are valid.
-    EXPECT_TRUE(root->IsDrawnRenderSurfaceLayerListMember());
-    EXPECT_TRUE(child->IsDrawnRenderSurfaceLayerListMember());
+    EXPECT_TRUE(root->is_drawn_render_surface_layer_list_member());
+    EXPECT_TRUE(child->is_drawn_render_surface_layer_list_member());
 
     EXPECT_OCCLUSION_EQ(
         Occlusion(child->DrawTransform(), SimpleEnclosedRegion(),
@@ -109,8 +109,8 @@
     RenderSurfaceImpl* surface = child->render_surface();
 
     // Verify the draw properties are valid.
-    EXPECT_TRUE(root->IsDrawnRenderSurfaceLayerListMember());
-    EXPECT_TRUE(child->IsDrawnRenderSurfaceLayerListMember());
+    EXPECT_TRUE(root->is_drawn_render_surface_layer_list_member());
+    EXPECT_TRUE(child->is_drawn_render_surface_layer_list_member());
     EXPECT_TRUE(child->has_render_surface());
     EXPECT_EQ(child->render_surface(), child->render_target());
 
@@ -177,8 +177,8 @@
     LayerImpl* mask = child->mask_layer();
 
     // Verify the draw properties are valid.
-    EXPECT_TRUE(root->IsDrawnRenderSurfaceLayerListMember());
-    EXPECT_TRUE(child->IsDrawnRenderSurfaceLayerListMember());
+    EXPECT_TRUE(root->is_drawn_render_surface_layer_list_member());
+    EXPECT_TRUE(child->is_drawn_render_surface_layer_list_member());
     EXPECT_TRUE(child->has_render_surface());
     EXPECT_EQ(child->render_surface(), child->render_target());
 
@@ -318,8 +318,8 @@
     LayerImpl* mask = child->mask_layer();
 
     // Verify the draw properties are valid.
-    EXPECT_TRUE(root->IsDrawnRenderSurfaceLayerListMember());
-    EXPECT_TRUE(child->IsDrawnRenderSurfaceLayerListMember());
+    EXPECT_TRUE(root->is_drawn_render_surface_layer_list_member());
+    EXPECT_TRUE(child->is_drawn_render_surface_layer_list_member());
     EXPECT_TRUE(child->has_render_surface());
     EXPECT_EQ(child->render_surface(), child->render_target());
 
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index 9963c87..858506a 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -78,7 +78,6 @@
       needs_full_tree_sync_(true),
       next_activation_forces_redraw_(false),
       has_ever_been_drawn_(false),
-      render_surface_layer_list_id_(0),
       have_scroll_event_handlers_(false),
       event_listener_properties_(),
       top_controls_shrink_blink_size_(false),
@@ -818,8 +817,6 @@
         (layer_tree_host_impl_->GetDrawMode() !=
          DRAW_MODE_RESOURCELESS_SOFTWARE);
 
-    ++render_surface_layer_list_id_;
-
     LayerTreeHostCommon::CalcDrawPropsImplInputs inputs(
         root_layer(), DrawViewportSize(),
         layer_tree_host_impl_->DrawTransform(), device_scale_factor(),
@@ -830,8 +827,7 @@
         settings().can_use_lcd_text, settings().layers_always_allowed_lcd_text,
         can_render_to_separate_surface,
         settings().layer_transforms_should_scale_layer_contents,
-        &render_surface_layer_list_, render_surface_layer_list_id_,
-        &property_trees_);
+        &render_surface_layer_list_, &property_trees_);
     LayerTreeHostCommon::CalculateDrawProperties(&inputs);
     if (const char* client_name = GetClientNameForMetrics()) {
       UMA_HISTOGRAM_COUNTS(
@@ -938,7 +934,7 @@
     size_t layers_updated_count = 0;
     bool tile_priorities_updated = false;
     for (PictureLayerImpl* layer : picture_layers_) {
-      if (!layer->IsDrawnRenderSurfaceLayerListMember())
+      if (!layer->is_drawn_render_surface_layer_list_member())
         continue;
       ++layers_updated_count;
       tile_priorities_updated |= layer->UpdateTiles();
@@ -969,10 +965,6 @@
   property_trees_.transform_tree.set_source_to_parent_updates_allowed(false);
 }
 
-void LayerTreeImpl::IncrementRenderSurfaceListIdForTesting() {
-  render_surface_layer_list_id_++;
-}
-
 const LayerImplList& LayerTreeImpl::RenderSurfaceLayerList() const {
   // If this assert triggers, then the list is dirty.
   DCHECK(!needs_update_draw_properties_);
@@ -1615,7 +1607,7 @@
     const LayerImpl* layer,
     const TransformTree& transform_tree) {
   DCHECK(layer->render_surface());
-  return layer->IsDrawnRenderSurfaceLayerListMember()
+  return layer->is_drawn_render_surface_layer_list_member()
              ? layer->render_surface()->screen_space_transform()
              : transform_tree.ToScreenSpaceTransformWithoutSublayerScale(
                    layer->render_surface()->TransformTreeIndex());
@@ -1762,7 +1754,7 @@
     LayerImpl* layer) {
   return layer->scrolls_drawn_descendant() ||
          (layer->ToScrollbarLayer() &&
-          layer->IsDrawnRenderSurfaceLayerListMember());
+          layer->is_drawn_render_surface_layer_list_member());
 }
 
 struct FindScrollingLayerOrScrollbarLayerFunctor {
@@ -1784,7 +1776,7 @@
 
 struct HitTestVisibleScrollableOrTouchableFunctor {
   bool operator()(LayerImpl* layer) const {
-    return layer->IsDrawnRenderSurfaceLayerListMember() ||
+    return layer->is_drawn_render_surface_layer_list_member() ||
            ScrollsOrScrollbarAnyDrawnRenderSurfaceLayerListMember(layer) ||
            !layer->touch_event_handler_region().IsEmpty();
   }
diff --git a/cc/trees/layer_tree_impl.h b/cc/trees/layer_tree_impl.h
index f90bf0f2..15d0a40 100644
--- a/cc/trees/layer_tree_impl.h
+++ b/cc/trees/layer_tree_impl.h
@@ -275,7 +275,6 @@
   // text may cause invalidations, so should only be done after a commit.
   bool UpdateDrawProperties(bool update_lcd_text);
   void BuildPropertyTreesForTesting();
-  void IncrementRenderSurfaceListIdForTesting();
 
   void set_needs_update_draw_properties() {
     needs_update_draw_properties_ = true;
@@ -402,10 +401,6 @@
     return surface_layers_;
   }
 
-  int current_render_surface_list_id() const {
-    return render_surface_layer_list_id_;
-  }
-
   LayerImpl* FindFirstScrollingLayerOrScrollbarLayerThatIsHitByPoint(
       const gfx::PointF& screen_space_point);
 
@@ -578,8 +573,6 @@
 
   UIResourceRequestQueue ui_resource_request_queue_;
 
-  int render_surface_layer_list_id_;
-
   bool have_scroll_event_handlers_;
   EventListenerProperties event_listener_properties_[static_cast<size_t>(
       EventListenerClass::kNumClasses)];
diff --git a/cc/trees/layer_tree_impl_unittest.cc b/cc/trees/layer_tree_impl_unittest.cc
index 44b1f1e..2a1547f 100644
--- a/cc/trees/layer_tree_impl_unittest.cc
+++ b/cc/trees/layer_tree_impl_unittest.cc
@@ -2116,7 +2116,7 @@
       host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
           test_point);
   EXPECT_FALSE(result_layer);
-  EXPECT_FALSE(test_layer->IsDrawnRenderSurfaceLayerListMember());
+  EXPECT_FALSE(test_layer->is_drawn_render_surface_layer_list_member());
   EXPECT_TRANSFORMATION_MATRIX_EQ(
       expected_screen_space_transform,
       draw_property_utils::ScreenSpaceTransform(
@@ -2138,7 +2138,7 @@
           test_point);
   ASSERT_TRUE(result_layer);
   ASSERT_EQ(test_layer, result_layer);
-  EXPECT_FALSE(result_layer->IsDrawnRenderSurfaceLayerListMember());
+  EXPECT_FALSE(result_layer->is_drawn_render_surface_layer_list_member());
   EXPECT_TRANSFORMATION_MATRIX_EQ(
       expected_screen_space_transform,
       draw_property_utils::ScreenSpaceTransform(
diff --git a/cc/trees/occlusion_tracker_unittest.cc b/cc/trees/occlusion_tracker_unittest.cc
index 9b0e7f9..8b54ce2 100644
--- a/cc/trees/occlusion_tracker_unittest.cc
+++ b/cc/trees/occlusion_tracker_unittest.cc
@@ -229,10 +229,8 @@
 
     FakeLayerTreeHostImpl::RecursiveUpdateNumChildren(root);
 
-    root->layer_tree_impl()->IncrementRenderSurfaceListIdForTesting();
     LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
-        root, root->bounds(), &render_surface_layer_list_impl_,
-        root->layer_tree_impl()->current_render_surface_list_id());
+        root, root->bounds(), &render_surface_layer_list_impl_);
     inputs.can_adjust_raster_scales = true;
     LayerTreeHostCommon::CalculateDrawProperties(&inputs);
 
diff --git a/cc/trees/property_tree_builder.cc b/cc/trees/property_tree_builder.cc
index 081778c..a265b4e 100644
--- a/cc/trees/property_tree_builder.cc
+++ b/cc/trees/property_tree_builder.cc
@@ -1040,6 +1040,27 @@
   property_trees->scroll_tree.set_needs_update(false);
 }
 
+#if DCHECK_IS_ON()
+static void CheckScrollAndClipPointersForLayer(Layer* layer) {
+  if (!layer)
+    return;
+
+  if (layer->scroll_children()) {
+    for (std::set<Layer*>::iterator it = layer->scroll_children()->begin();
+         it != layer->scroll_children()->end(); ++it) {
+      DCHECK_EQ((*it)->scroll_parent(), layer);
+    }
+  }
+
+  if (layer->clip_children()) {
+    for (std::set<Layer*>::iterator it = layer->clip_children()->begin();
+         it != layer->clip_children()->end(); ++it) {
+      DCHECK_EQ((*it)->clip_parent(), layer);
+    }
+  }
+}
+#endif
+
 void PropertyTreeBuilder::BuildPropertyTrees(
     Layer* root_layer,
     const Layer* page_scale_layer,
@@ -1062,6 +1083,10 @@
       outer_viewport_scroll_layer, overscroll_elasticity_layer,
       elastic_overscroll, page_scale_factor, device_scale_factor, viewport,
       device_transform, property_trees, color);
+#if DCHECK_IS_ON()
+  for (auto* layer : *root_layer->layer_tree_host())
+    CheckScrollAndClipPointersForLayer(layer);
+#endif
 }
 
 void PropertyTreeBuilder::BuildPropertyTrees(
diff --git a/cc/trees/tree_synchronizer.cc b/cc/trees/tree_synchronizer.cc
index d055f4c..c726f83 100644
--- a/cc/trees/tree_synchronizer.cc
+++ b/cc/trees/tree_synchronizer.cc
@@ -124,32 +124,6 @@
       SynchronizeTreesRecursiveInternal(old_layers, old_root, tree_impl));
 }
 
-#if DCHECK_IS_ON()
-static void CheckScrollAndClipPointersForLayer(Layer* layer) {
-  if (!layer)
-    return;
-
-  if (layer->scroll_children()) {
-    for (std::set<Layer*>::iterator it = layer->scroll_children()->begin();
-         it != layer->scroll_children()->end(); ++it) {
-      DCHECK_EQ((*it)->scroll_parent(), layer);
-    }
-  }
-
-  if (layer->clip_children()) {
-    for (std::set<Layer*>::iterator it = layer->clip_children()->begin();
-         it != layer->clip_children()->end(); ++it) {
-      DCHECK_EQ((*it)->clip_parent(), layer);
-    }
-  }
-}
-
-static void CheckScrollAndClipPointers(LayerTreeHost* host) {
-  for (auto* layer : *host)
-    CheckScrollAndClipPointersForLayer(layer);
-}
-#endif
-
 template <typename LayerType>
 static void PushLayerPropertiesInternal(
     std::unordered_set<LayerType*> layers_that_should_push_properties,
@@ -171,11 +145,6 @@
                                            LayerTreeImpl* impl_tree) {
   PushLayerPropertiesInternal(host_tree->LayersThatShouldPushProperties(),
                               impl_tree);
-
-#if DCHECK_IS_ON()
-  if (host_tree->root_layer())
-    CheckScrollAndClipPointers(host_tree);
-#endif
 }
 
 }  // namespace cc
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
index 1bc8c3e..2aac3c79 100644
--- a/chrome/android/java/AndroidManifest.xml
+++ b/chrome/android/java/AndroidManifest.xml
@@ -307,12 +307,10 @@
             android:label="@string/fre_label"
             android:launchMode="singleTop"
             android:windowSoftInputMode="stateHidden|adjustPan"
-            android:screenOrientation="portrait"
             android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize">
         </activity>
         <activity android:name="org.chromium.chrome.browser.signin.AccountSigninActivity"
             android:theme="@style/MainTheme"
-            android:screenOrientation="portrait"
             android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize">
         </activity>
         <activity android:name="org.chromium.chrome.browser.preferences.Preferences"
@@ -360,11 +358,6 @@
             android:label="@string/bookmark_choose_folder"
             android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize">
         </activity>
-        <activity android:name="org.chromium.chrome.browser.bookmarks.BookmarkSigninActivity"
-            android:theme="@style/BookmarkDialogWhite"
-            android:screenOrientation="portrait"
-            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize">
-        </activity>
 
         <!--
             Activities for webapps.
diff --git a/chrome/android/java/res/drawable-hdpi/add_circle_blue.png b/chrome/android/java/res/drawable-hdpi/add_circle_blue.png
index c98a6a0..2a5b8df 100644
--- a/chrome/android/java/res/drawable-hdpi/add_circle_blue.png
+++ b/chrome/android/java/res/drawable-hdpi/add_circle_blue.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/add_circle_blue.png b/chrome/android/java/res/drawable-mdpi/add_circle_blue.png
index fe576c7..58c0b5d 100644
--- a/chrome/android/java/res/drawable-mdpi/add_circle_blue.png
+++ b/chrome/android/java/res/drawable-mdpi/add_circle_blue.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/add_circle_blue.png b/chrome/android/java/res/drawable-xhdpi/add_circle_blue.png
index cf0e8ab1..f997bf7 100644
--- a/chrome/android/java/res/drawable-xhdpi/add_circle_blue.png
+++ b/chrome/android/java/res/drawable-xhdpi/add_circle_blue.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/add_circle_blue.png b/chrome/android/java/res/drawable-xxhdpi/add_circle_blue.png
index a8d2d27a6..ec1a265 100644
--- a/chrome/android/java/res/drawable-xxhdpi/add_circle_blue.png
+++ b/chrome/android/java/res/drawable-xxhdpi/add_circle_blue.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/add_circle_blue.png b/chrome/android/java/res/drawable-xxxhdpi/add_circle_blue.png
index b9a6aa8..1f01536 100644
--- a/chrome/android/java/res/drawable-xxxhdpi/add_circle_blue.png
+++ b/chrome/android/java/res/drawable-xxxhdpi/add_circle_blue.png
Binary files differ
diff --git a/chrome/android/java/res/layout/account_signin_choice_description_view.xml b/chrome/android/java/res/layout/account_signin_choice_description_view.xml
deleted file mode 100644
index 5a10a94..0000000
--- a/chrome/android/java/res/layout/account_signin_choice_description_view.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2016 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
-
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/signin_choice_description"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:padding="16dp"
-    android:lineSpacingMultiplier="1.4"
-    android:text="@string/signin_account_choice_description"
-    android:textColor="@color/default_text_color"
-    android:textSize="@dimen/fre_normal_text_size"/>
\ No newline at end of file
diff --git a/chrome/android/java/res/layout/account_signin_view.xml b/chrome/android/java/res/layout/account_signin_view.xml
index b1467f7..d0934926 100644
--- a/chrome/android/java/res/layout/account_signin_view.xml
+++ b/chrome/android/java/res/layout/account_signin_view.xml
@@ -17,42 +17,51 @@
         android:layout_marginBottom="52dp">
 
         <!-- The view that allows the user to choose the sign in account -->
-        <LinearLayout
-            android:id="@+id/signin_choose_account_view"
+        <org.chromium.chrome.browser.signin.AccountSigninChooseView
+            android:id="@+id/account_signin_choose_view"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
-            android:orientation="vertical">
+            android:scrollbars="none"
+            android:requiresFadingEdge="vertical"
+            android:fadingEdgeLength="48dp">
 
-            <!-- The layout_width/layout_height is set to 16/9 dynamically in Java -->
-            <TextView
-                android:id="@+id/signin_title"
+            <LinearLayout
+                android:id="@+id/account_signin_choose_view_root_child_view"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:gravity="bottom"
-                android:paddingStart="16dp"
-                android:paddingEnd="16dp" 
-                android:paddingBottom="16dp"
-                android:background="@color/signin_head_background"
-                android:textColor="@color/default_text_color"
-                android:textSize="@dimen/fre_title_text_size"
-                android:text="@string/sign_in_to_chrome"/>
+                android:orientation="vertical">
 
-            <View
-                android:layout_width="match_parent"
-                android:layout_height="1dp"
-                android:background="@color/signin_border_line_color"
-                android:alpha="0.08"/>
+                <!-- The layout_width/layout_height is set to 16/9 dynamically in Java -->
+                <TextView 
+                    android:id="@+id/signin_title"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:gravity="bottom"
+                    android:paddingStart="@dimen/signin_chooser_padding"
+                    android:paddingEnd="@dimen/signin_chooser_padding"
+                    android:paddingBottom="@dimen/signin_chooser_padding"
+                    android:background="@color/signin_head_background"
+                    android:textColor="@color/default_text_color"
+                    android:textSize="@dimen/fre_title_text_size"
+                    android:text="@string/sign_in_to_chrome"/>
 
-            <org.chromium.chrome.browser.signin.AccountListView
-                android:id="@+id/signin_account_list"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:divider="@null"
-                android:dividerHeight="0dp"
-                android:scrollbars="none"
-                android:requiresFadingEdge="vertical"
-                android:fadingEdgeLength="48dp"/>
-        </LinearLayout>
+                <View 
+                    android:layout_width="match_parent"
+                    android:layout_height="1dp"
+                    android:background="@color/signin_border_line_color"
+                    android:alpha="0.08"/>
+
+                <TextView 
+                    android:id="@+id/signin_choice_description"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:padding="@dimen/signin_chooser_padding"
+                    android:lineSpacingMultiplier="1.4"
+                    android:text="@string/signin_account_choice_description"
+                    android:textColor="@color/default_text_color"
+                    android:textSize="@dimen/fre_normal_text_size"/>
+            </LinearLayout>
+        </org.chromium.chrome.browser.signin.AccountSigninChooseView>
 
         <!-- The view that allows the user to confirm signed in account, sync and service personalization -->
         <org.chromium.chrome.browser.signin.AccountSigninConfirmationView
diff --git a/chrome/android/java/res/layout/recent_tabs_sync_promo.xml b/chrome/android/java/res/layout/recent_tabs_sync_promo.xml
deleted file mode 100644
index 8c226e5..0000000
--- a/chrome/android/java/res/layout/recent_tabs_sync_promo.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2015 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
-
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:chrome="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:orientation="vertical"
-    android:paddingTop="10dp"
-    android:paddingBottom="28dp" >
-
-    <TextView
-        android:id="@+id/text_view"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:textSize="14sp" />
-
-    <org.chromium.ui.widget.ButtonCompat
-        android:id="@+id/enable_sync_button"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="24dp"
-        android:text="@string/ntp_recent_tabs_sync_enable_sync_button"
-        android:textColor="#fff"
-        chrome:buttonColor="@color/light_active_color" />
-
-</LinearLayout>
diff --git a/chrome/android/java/res/layout/bookmark_promo_header.xml b/chrome/android/java/res/layout/signin_and_sync_view.xml
similarity index 82%
rename from chrome/android/java/res/layout/bookmark_promo_header.xml
rename to chrome/android/java/res/layout/signin_and_sync_view.xml
index 26cf503..07c2257 100644
--- a/chrome/android/java/res/layout/bookmark_promo_header.xml
+++ b/chrome/android/java/res/layout/signin_and_sync_view.xml
@@ -1,10 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright 2015 The Chromium Authors. All rights reserved.
-
+<!-- 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.
--->
+     found in the LICENSE file. -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:chrome="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
@@ -16,7 +13,7 @@
         android:id="@+id/title"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:text="@string/bookmark_sign_in_promo_title"
+        android:layout_marginBottom="8dp"
         android:textColor="@color/default_text_color"
         android:textSize="16sp"
         android:textStyle="bold" />
@@ -25,8 +22,6 @@
         android:id="@+id/description"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_marginTop="8dp"
-        android:text="@string/bookmark_sign_in_promo_description"
         android:textColor="@color/default_text_color"
         android:textSize="14sp" />
 
@@ -43,7 +38,7 @@
             style="@style/ButtonCompatBorderless"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:text="@string/bookmark_sign_in_promo_no_thanks"
+            android:text="@string/no_thanks"
             android:textAllCaps="true"
             android:textColor="@color/light_active_color"
             android:textSize="15sp" />
@@ -52,7 +47,6 @@
             android:id="@+id/sign_in"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:text="@string/bookmark_sign_in_promo_sign_in"
             android:textAllCaps="true"
             android:textColor="@android:color/white"
             android:textSize="15sp"
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index abf0881..0da9eea 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -166,6 +166,8 @@
     <!-- The Account Signin page appears in the First Run Experience (amongst other places), so uses
     a lot of the fre_* dimensions for consistency. -->
     <dimen name="signin_image_carousel_width">240dp</dimen>
+    <dimen name="signin_chooser_padding">16dp</dimen>
+    <dimen name="signin_screen_top_padding">50dp</dimen>
     
     <!-- Autofill card unmasking prompt dimensions -->
     <dimen name="autofill_card_unmask_tooltip_horizontal_padding">16dp</dimen>
@@ -267,7 +269,6 @@
 
     <!-- Recent tabs page -->
     <dimen name="recent_tabs_visible_separator_padding">8dp</dimen>
-    <dimen name="recent_tabs_promo_padding">16dp</dimen>
 
     <!-- Snackbars -->
     <dimen name="snackbar_min_height">48dp</dimen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkPromoHeader.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkPromoHeader.java
index 1a0ced1..50ed7c3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkPromoHeader.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkPromoHeader.java
@@ -5,18 +5,16 @@
 package org.chromium.chrome.browser.bookmarks;
 
 import android.content.Context;
-import android.content.Intent;
 import android.content.SharedPreferences;
 import android.preference.PreferenceManager;
 import android.support.v7.widget.RecyclerView;
 import android.support.v7.widget.RecyclerView.ViewHolder;
-import android.view.LayoutInflater;
 import android.view.View;
-import android.view.View.OnClickListener;
 import android.view.ViewGroup;
 
 import org.chromium.base.metrics.RecordUserAction;
-import org.chromium.chrome.R;
+import org.chromium.chrome.browser.signin.SigninAccessPoint;
+import org.chromium.chrome.browser.signin.SigninAndSyncView;
 import org.chromium.chrome.browser.signin.SigninManager;
 import org.chromium.chrome.browser.signin.SigninManager.SignInStateObserver;
 import org.chromium.sync.AndroidSyncSettings;
@@ -98,26 +96,17 @@
      *         {@link RecyclerView}.
      */
     ViewHolder createHolder(ViewGroup parent) {
-        ViewGroup promoHeader = (ViewGroup) LayoutInflater.from(mContext)
-                .inflate(R.layout.bookmark_promo_header, parent, false);
-
-        promoHeader.findViewById(R.id.no_thanks).setOnClickListener(new OnClickListener() {
+        SigninAndSyncView.Listener listener = new SigninAndSyncView.Listener() {
             @Override
-            public void onClick(View view) {
+            public void onViewDismissed() {
                 RecordUserAction.record("Stars_SignInPromoHeader_Dismissed");
                 setSigninPromoDeclined();
                 updateShouldShow(true);
             }
-        });
+        };
 
-        promoHeader.findViewById(R.id.sign_in).setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                mContext.startActivity(new Intent(mContext, BookmarkSigninActivity.class));
-            }
-        });
-
-        return new ViewHolder(promoHeader) {};
+        View view = new SigninAndSyncView(mContext, listener, SigninAccessPoint.BOOKMARK_MANAGER);
+        return new ViewHolder(view) {};
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSigninActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSigninActivity.java
deleted file mode 100644
index e84fcd7..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSigninActivity.java
+++ /dev/null
@@ -1,149 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.bookmarks;
-
-import android.os.Bundle;
-
-import org.chromium.base.ObserverList;
-import org.chromium.base.metrics.RecordUserAction;
-import org.chromium.chrome.browser.firstrun.ProfileDataCache;
-import org.chromium.chrome.browser.ntp.RecentTabsPromoView;
-import org.chromium.chrome.browser.ntp.RecentTabsPromoView.SyncPromoModel;
-import org.chromium.chrome.browser.ntp.RecentTabsPromoView.UserActionListener;
-import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.signin.SigninAccessPoint;
-import org.chromium.chrome.browser.signin.SigninManager;
-import org.chromium.chrome.browser.signin.SigninManager.SignInStateObserver;
-import org.chromium.chrome.browser.sync.ProfileSyncService;
-import org.chromium.sync.AndroidSyncSettings;
-import org.chromium.sync.AndroidSyncSettings.AndroidSyncSettingsObserver;
-import org.chromium.sync.signin.ChromeSigninController;
-
-/**
- * Sign in promotion activity that is triggered from bookmark UI.
- */
-public class BookmarkSigninActivity extends BookmarkActivityBase implements
-        AndroidSyncSettingsObserver, SignInStateObserver, SyncPromoModel, UserActionListener {
-    private SigninManager mSignInManager;
-    private ProfileDataCache mProfileDataCache;
-    private final ObserverList<AndroidSyncSettingsObserver> mObservers =
-            new ObserverList<AndroidSyncSettingsObserver>();
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        if (savedInstanceState == null) {
-            RecordUserAction.record("Stars_SignInPromoActivity_Launched");
-        }
-
-        setContentView(new RecentTabsPromoView(this, this, this));
-
-        AndroidSyncSettings.registerObserver(this, this);
-
-        mSignInManager = SigninManager.get(this);
-        mSignInManager.addSignInStateObserver(this);
-
-        // This signin activity shouldn't be created if user is signed in already, but for just in
-        // case it was signed in just before onCreate somehow.
-        if (isSignedIn()) finish();
-    }
-
-    @Override
-    public void onDestroy() {
-        super.onDestroy();
-        AndroidSyncSettings.unregisterObserver(this, this);
-
-        mSignInManager.removeSignInStateObserver(this);
-        mSignInManager = null;
-
-        if (mProfileDataCache != null) {
-            mProfileDataCache.destroy();
-            mProfileDataCache = null;
-        }
-    }
-
-    // AndroidSyncSettingsObserver
-
-    @Override
-    public void androidSyncSettingsChanged() {
-        for (AndroidSyncSettingsObserver observer : mObservers) {
-            observer.androidSyncSettingsChanged();
-        }
-    }
-
-    // SignInStateObserver
-
-    @Override
-    public void onSignedIn() {
-        androidSyncSettingsChanged();
-        finish();
-    }
-
-    @Override
-    public void onSignedOut() {
-        assert false : "onSignedOut() called on signin activity.";
-    }
-
-    // SyncPromoModel
-
-    @Override
-    public boolean isSyncEnabled() {
-        return AndroidSyncSettings.isSyncEnabled(this);
-    }
-
-    @Override
-    public boolean isSignedIn() {
-        return ChromeSigninController.get(this).isSignedIn();
-    }
-
-    @Override
-    public void enableSync() {
-        ProfileSyncService syncService = ProfileSyncService.get();
-        if (syncService != null) {
-            syncService.requestStart();
-        }
-    }
-
-    @Override
-    public void registerForSyncUpdates(AndroidSyncSettingsObserver changeListener) {
-        mObservers.addObserver(changeListener);
-    }
-
-    @Override
-    public void unregisterForSyncUpdates(AndroidSyncSettingsObserver changeListener) {
-        mObservers.removeObserver(changeListener);
-    }
-
-    // UserActionListener
-
-    @Override
-    public void onAccountSelectionConfirmed() {
-        RecordUserAction.record("Stars_SignInPromoActivity_SignedIn");
-        RecordUserAction.record("Signin_Signin_FromBookmarkManager");
-    }
-
-    @Override
-    public void onNewAccount() {
-        RecordUserAction.record("Stars_SignInPromoActivity_NewAccount");
-    }
-
-    @Override
-    public void onAccountSelectionCancelled() {
-        finish();
-    };
-
-    @Override
-    public ProfileDataCache getProfileDataCache() {
-        if (mProfileDataCache == null) {
-            mProfileDataCache = new ProfileDataCache(this, Profile.getLastUsedProfile());
-        }
-        return mProfileDataCache;
-    }
-
-    @Override
-    public int getAccessPoint() {
-        return SigninAccessPoint.BOOKMARK_MANAGER;
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunView.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunView.java
index d360389..74f8582 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunView.java
@@ -48,12 +48,13 @@
         return true;
     }
 
-    protected boolean isDynamicPaddingEnabled() {
-        return true;
-    }
-
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        // There was a requirement to have the titles and images of all of the first run experience
+        // pages to be vertically aligned so the transitions between pages look nice.
+        // The other requirement is for an alternate layout in horizontal mode for screens of a
+        // certain size. These are why the padding is set manually.
+
         // This assumes that view's layout_width is set to match_parent.
         assert MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY;
 
@@ -96,12 +97,10 @@
         }
 
         // Add padding to get it roughly centered.
-        if (isDynamicPaddingEnabled()) {
-            int topPadding = Math.max(0, (height / 2) - halfContentHeight);
+        int topPadding = Math.max(0, (height / 2) - halfContentHeight);
 
-            mMainLayout.setPadding(mMainLayout.getPaddingLeft(), topPadding,
-                    mMainLayout.getPaddingRight(), mMainLayout.getPaddingBottom());
-        }
+        mMainLayout.setPadding(mMainLayout.getPaddingLeft(), topPadding,
+                mMainLayout.getPaddingRight(), mMainLayout.getPaddingBottom());
 
         ApiCompatibilityUtils.setPaddingRelative(mImageAndContent,
                 imageAndContentPaddingStart,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
index 6991058..d7fda1d5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
@@ -23,6 +23,7 @@
 import org.chromium.base.BaseSwitches;
 import org.chromium.base.CommandLine;
 import org.chromium.base.ContentUriUtils;
+import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
 import org.chromium.base.PathUtils;
 import org.chromium.base.ResourceExtractor;
@@ -184,6 +185,8 @@
         ThreadUtils.assertOnUiThread();
         if (mPreInflationStartupComplete) return;
 
+        ContextUtils.initApplicationContext(mApplication);
+
         // Ensure critical files are available, so they aren't blocked on the file-system
         // behind long-running accesses in next phase.
         // Don't do any large file access here!
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/router/cast/CastSessionImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/media/router/cast/CastSessionImpl.java
index 01aff0f5..cef866a6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/router/cast/CastSessionImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/router/cast/CastSessionImpl.java
@@ -142,8 +142,10 @@
         }
 
         Intent contentIntent = Tab.createBringTabToFrontIntent(tabId);
-        contentIntent.putExtra(MediaNotificationUma.INTENT_EXTRA_NAME,
-                MediaNotificationUma.SOURCE_PRESENTATION);
+        if (contentIntent != null) {
+            contentIntent.putExtra(MediaNotificationUma.INTENT_EXTRA_NAME,
+                    MediaNotificationUma.SOURCE_PRESENTATION);
+        }
         mNotificationBuilder = new MediaNotificationInfo.Builder()
                 .setPaused(false)
                 .setOrigin(origin)
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaSessionTabHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaSessionTabHelper.java
index 0484774a..083d709 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaSessionTabHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaSessionTabHelper.java
@@ -114,8 +114,10 @@
                 }
 
                 Intent contentIntent = Tab.createBringTabToFrontIntent(mTab.getId());
-                contentIntent.putExtra(MediaNotificationUma.INTENT_EXTRA_NAME,
-                        MediaNotificationUma.SOURCE_MEDIA);
+                if (contentIntent != null) {
+                    contentIntent.putExtra(MediaNotificationUma.INTENT_EXTRA_NAME,
+                            MediaNotificationUma.SOURCE_MEDIA);
+                }
 
                 mNotificationInfoBuilder =
                         new MediaNotificationInfo.Builder()
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
index aa250af..a0c2500d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
@@ -80,6 +80,8 @@
 import org.chromium.ui.base.DeviceFormFactor;
 import org.chromium.ui.base.PageTransition;
 
+import java.util.HashSet;
+import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
 import jp.tomorrowkey.android.gifplayer.BaseGifImage;
@@ -455,10 +457,32 @@
         }
 
         @Override
-        public boolean isOfflineAvailable(String pageUrl) {
-            if (mIsDestroyed || !isNtpOfflinePagesEnabled()) return false;
-            if (isLocalUrl(pageUrl)) return true;
-            return OfflinePageBridge.getForProfile(mProfile).offlinePageExists(pageUrl);
+        public void getUrlsAvailableOffline(
+                Set<String> pageUrls, final Callback<Set<String>> callback) {
+            final Set<String> urlsAvailableOffline = new HashSet<>();
+            if (mIsDestroyed || !isNtpOfflinePagesEnabled()) {
+                callback.onResult(urlsAvailableOffline);
+                return;
+            }
+
+            HashSet<String> urlsToCheckForOfflinePage = new HashSet<>();
+
+            for (String pageUrl : pageUrls) {
+                if (isLocalUrl(pageUrl)) {
+                    urlsAvailableOffline.add(pageUrl);
+                } else {
+                    urlsToCheckForOfflinePage.add(pageUrl);
+                }
+            }
+
+            OfflinePageBridge.getForProfile(mProfile).checkPagesExistOffline(
+                    urlsToCheckForOfflinePage, new Callback<Set<String>>() {
+                        @Override
+                        public void onResult(Set<String> urlsWithOfflinePages) {
+                            urlsAvailableOffline.addAll(urlsWithOfflinePages);
+                            callback.onResult(urlsAvailableOffline);
+                        }
+                    });
         }
 
         @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
index 978476c3..bb726325 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
@@ -32,6 +32,7 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import org.chromium.base.Callback;
 import org.chromium.base.Log;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.metrics.RecordUserAction;
@@ -54,6 +55,10 @@
 import org.chromium.chrome.browser.widget.RoundedIconGenerator;
 import org.chromium.ui.base.DeviceFormFactor;
 
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
 import jp.tomorrowkey.android.gifplayer.BaseGifImage;
 
 /**
@@ -198,10 +203,11 @@
                 IconAvailabilityCallback callback);
 
         /**
-         * Checks if the page with the given URL is available offline.
-         * @param pageUrl The URL of the site whose offline availability is requested.
+         * Checks if the pages with the given URLs are available offline.
+         * @param pageUrls The URLs of the sites whose offline availability is requested.
+         * @param callback Fired when the results are available.
          */
-        boolean isOfflineAvailable(String pageUrl);
+        void getUrlsAvailableOffline(Set<String> pageUrls, Callback<Set<String>> callback);
 
         /**
          * Called when the user clicks on the logo.
@@ -805,7 +811,22 @@
 
     @Override
     public void onMostVisitedURLsAvailable(
-            String[] titles, String[] urls, String[] whitelistIconPaths) {
+            final String[] titles, final String[] urls, final String[] whitelistIconPaths) {
+        Set<String> urlSet = new HashSet<>(Arrays.asList(urls));
+
+        // TODO(https://crbug.com/607573): We should show offline-available content in a nonblocking
+        // way so that responsiveness of the NTP does not depend on ready availability of offline
+        // pages.
+        mManager.getUrlsAvailableOffline(urlSet, new Callback<Set<String>>() {
+            @Override
+            public void onResult(Set<String> offlineUrls) {
+                onOfflineUrlsAvailable(titles, urls, whitelistIconPaths, offlineUrls);
+            }
+        });
+    }
+
+    private void onOfflineUrlsAvailable(final String[] titles, final String[] urls,
+            final String[] whitelistIconPaths, final Set<String> offlineUrls) {
         mMostVisitedLayout.removeAllViews();
 
         MostVisitedItem[] oldItems = mMostVisitedItems;
@@ -820,7 +841,7 @@
             final String url = urls[i];
             final String title = titles[i];
             final String whitelistIconPath = whitelistIconPaths[i];
-            boolean offlineAvailable = mManager.isOfflineAvailable(url);
+            boolean offlineAvailable = offlineUrls.contains(url);
 
             // Look for an existing item to reuse.
             MostVisitedItem item = null;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsManager.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsManager.java
index c799319..981530e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsManager.java
@@ -9,25 +9,20 @@
 import android.graphics.Bitmap;
 import android.preference.PreferenceManager;
 
-import org.chromium.base.ObserverList;
 import org.chromium.base.ThreadUtils;
 import org.chromium.chrome.browser.UrlConstants;
 import org.chromium.chrome.browser.favicon.FaviconHelper;
 import org.chromium.chrome.browser.favicon.FaviconHelper.FaviconImageCallback;
-import org.chromium.chrome.browser.firstrun.ProfileDataCache;
 import org.chromium.chrome.browser.invalidation.InvalidationController;
 import org.chromium.chrome.browser.metrics.StartupMetrics;
 import org.chromium.chrome.browser.ntp.ForeignSessionHelper.ForeignSession;
 import org.chromium.chrome.browser.ntp.ForeignSessionHelper.ForeignSessionCallback;
 import org.chromium.chrome.browser.ntp.ForeignSessionHelper.ForeignSessionTab;
-import org.chromium.chrome.browser.ntp.RecentTabsPromoView.SyncPromoModel;
 import org.chromium.chrome.browser.ntp.RecentlyClosedBridge.RecentlyClosedCallback;
 import org.chromium.chrome.browser.ntp.RecentlyClosedBridge.RecentlyClosedTab;
 import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.signin.SigninAccessPoint;
 import org.chromium.chrome.browser.signin.SigninManager;
 import org.chromium.chrome.browser.signin.SigninManager.SignInStateObserver;
-import org.chromium.chrome.browser.sync.ProfileSyncService;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.sync.AndroidSyncSettings;
@@ -40,8 +35,7 @@
 /**
  * Provides the domain logic and data for RecentTabsPage and RecentTabsRowAdapter.
  */
-public class RecentTabsManager implements AndroidSyncSettingsObserver, SignInStateObserver,
-        SyncPromoModel {
+public class RecentTabsManager implements AndroidSyncSettingsObserver, SignInStateObserver {
 
     /**
      * Implement this to receive updates when the page contents change.
@@ -60,8 +54,6 @@
     private final Profile mProfile;
     private final Tab mTab;
     private final Context mContext;
-    private final ObserverList<AndroidSyncSettingsObserver> mObservers =
-            new ObserverList<AndroidSyncSettingsObserver>();
 
     private FaviconHelper mFaviconHelper;
     private ForeignSessionHelper mForeignSessionHelper;
@@ -71,7 +63,6 @@
     private RecentlyClosedBridge mRecentlyClosedBridge;
     private SigninManager mSignInManager;
     private UpdatedCallback mUpdatedCallback;
-    private ProfileDataCache mProfileDataCache;
     private boolean mIsDestroyed;
 
     /**
@@ -124,11 +115,6 @@
         mNewTabPagePrefs.destroy();
         mNewTabPagePrefs = null;
 
-        if (mProfileDataCache != null) {
-            mProfileDataCache.destroy();
-            mProfileDataCache = null;
-        }
-
         InvalidationController.get(mContext).onRecentTabsPageClosed();
     }
 
@@ -461,52 +447,11 @@
                 if (mIsDestroyed) return;
                 updateForeignSessions();
                 postUpdate();
-                for (AndroidSyncSettingsObserver observer : mObservers) {
-                    observer.androidSyncSettingsChanged();
-                }
             }
         });
     }
 
-    // SyncPromoModel
-    @Override
-    public boolean isSyncEnabled() {
-        return AndroidSyncSettings.isSyncEnabled(mContext);
-    }
-
-    @Override
     public boolean isSignedIn() {
         return ChromeSigninController.get(mContext).isSignedIn();
     }
-
-    @Override
-    public void enableSync() {
-        ProfileSyncService syncService = ProfileSyncService.get();
-        if (syncService != null) {
-            syncService.requestStart();
-        }
-    }
-
-    @Override
-    public void registerForSyncUpdates(AndroidSyncSettingsObserver changeListener) {
-        mObservers.addObserver(changeListener);
-    }
-
-    @Override
-    public void unregisterForSyncUpdates(AndroidSyncSettingsObserver changeListener) {
-        mObservers.removeObserver(changeListener);
-    }
-
-    @Override
-    public ProfileDataCache getProfileDataCache() {
-        if (mProfileDataCache == null) {
-            mProfileDataCache = new ProfileDataCache(mContext, Profile.getLastUsedProfile());
-        }
-        return mProfileDataCache;
-    }
-
-    @Override
-    public int getAccessPoint() {
-        return SigninAccessPoint.RECENT_TABS;
-    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsPromoView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsPromoView.java
deleted file mode 100644
index 6e1c5a8..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsPromoView.java
+++ /dev/null
@@ -1,296 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.ntp;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.app.Activity;
-import android.app.FragmentManager;
-import android.graphics.Color;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.FrameLayout;
-import android.widget.TextView;
-
-import org.chromium.chrome.R;
-import org.chromium.chrome.browser.firstrun.ProfileDataCache;
-import org.chromium.chrome.browser.signin.AccountAdder;
-import org.chromium.chrome.browser.signin.AccountSigninView;
-import org.chromium.chrome.browser.signin.SigninManager;
-import org.chromium.sync.AndroidSyncSettings.AndroidSyncSettingsObserver;
-
-/**
- * Promo view on the recent tabs page that encourages the user to sign in to Chrome or enable sync.
- * This view handles three scenarios:
- *
- * 1. The user is not signed in: Shows the sign-in screen from first run.
- * 2. The user is signed in but sync is disabled: Displays a message encouraging the user
- *    to enable sync with a corresponding button.
- * 3. The user is signed in and sync is enabled: Displays a message instructing
- *    the user to sign in and open tabs on another device to use this awesome feature.
- */
-public class RecentTabsPromoView extends FrameLayout implements AndroidSyncSettingsObserver {
-
-    /**
-     * Interface definition for the model this view needs to interact with.
-     */
-    public interface SyncPromoModel {
-        /**
-         * @return Whether sync is enabled.
-         */
-        public boolean isSyncEnabled();
-
-        /**
-         * @return Whether the user is signed in.
-         */
-        public boolean isSignedIn();
-
-        /**
-         * Enables sync for the current signed in account.
-         */
-        public void enableSync();
-
-        /**
-         * Attaches a listener to sync state changes.
-         *
-         * @param changeListener The SyncStateChangedListener The object to register for sync
-         * updates.
-         */
-        public void registerForSyncUpdates(AndroidSyncSettingsObserver changeListener);
-
-        /**
-         * Removes a listener for sync state changes.
-         *
-         * @param changeListener The SyncStateChangedListener The object to unregister for sync
-         * updates.
-         */
-        public void unregisterForSyncUpdates(AndroidSyncSettingsObserver changeListener);
-
-        /**
-         * @return A ProfileDataCache to retrieve user account info.
-         */
-        public ProfileDataCache getProfileDataCache();
-
-        /**
-        * @return the access point of creating this view.
-        */
-        public int getAccessPoint();
-    }
-
-    /**
-     * Interface for listening user actions on this UI.
-     */
-    public interface UserActionListener {
-        /**
-         * Called when user confirms an account to sign-in.
-         */
-        void onAccountSelectionConfirmed();
-
-        /**
-         * Called when user attempts to create a new account.
-         */
-        void onNewAccount();
-
-        /**
-         * Called when a user cancels the account sign in process.
-         */
-        void onAccountSelectionCancelled();
-    }
-
-    private static final int PROMO_TYPE_SIGN_IN = 0;
-    private static final int PROMO_TYPE_SYNC_DISABLED = 1;
-    private static final int PROMO_TYPE_SYNC_ENABLED = 2;
-
-    private static final int TEXT_COLOR_NORMAL = 0xff333333;
-    private static final int TEXT_COLOR_LIGHT = 0xffa0a0a0;
-
-    private static final long FADE_DURATION_MS = 300L;
-
-    private Activity mActivity;
-    private SyncPromoModel mModel;
-    private UserActionListener mUserActionListener;
-
-    private View mPromo;
-    private int mPromoType = -1;
-    private Animator mFadeAnimation;
-
-    /**
-     * Constructor for use from Java.
-     *
-     * @param activity The Activity this view will be presented in.
-     * @param model The SyncPromoModel used to determine the state of sync and sign-in.
-     */
-    public RecentTabsPromoView(Activity activity, SyncPromoModel model,
-            UserActionListener userActionListener) {
-        super(activity);
-        mModel = model;
-        mActivity = activity;
-        mUserActionListener = userActionListener;
-        int sidePadding = getResources().getDimensionPixelOffset(R.dimen.recent_tabs_promo_padding);
-        setPadding(sidePadding, 0, sidePadding, 0);
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        mModel.registerForSyncUpdates(this);
-        configureForSyncState(false);
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        mModel.unregisterForSyncUpdates(this);
-    }
-
-    @Override
-    public void onWindowVisibilityChanged(int visibility) {
-        super.onWindowVisibilityChanged(visibility);
-        if (visibility == View.VISIBLE) {
-            configureForSyncState(false);
-        }
-    }
-
-    // AndroidSyncSettingsObserver
-    @Override
-    public void androidSyncSettingsChanged() {
-        configureForSyncState(true);
-    }
-
-    private void configureForSyncState(boolean animate) {
-        int desiredPromoType = getDesiredPromoType();
-        if (mPromo != null && mPromoType == desiredPromoType) {
-            return;
-        }
-
-        // In the rare case that the promo type changes while an animation is already underway,
-        // cancel the existing animation and show the new promo without animation. This is a rare
-        // case, and it's not worth the complexity (and bug potential) of implementing a three-way
-        // cross fade.
-        if (mFadeAnimation != null) {
-            mFadeAnimation.end();
-            animate = false;
-        }
-
-        if (animate && mPromoType == PROMO_TYPE_SIGN_IN) {
-            ((AccountSigninView) mPromo).switchToSignedMode();
-        }
-
-        final View oldPromo = mPromo;
-        mPromoType = desiredPromoType;
-        mPromo = createPromoView(desiredPromoType);
-
-        if (animate) {
-            // Fade in the new promo on top of the old one. Set the background color to white so
-            // the old promo effectively fades out as the new one fades in.
-            mPromo.setAlpha(0f);
-            mPromo.setBackgroundColor(Color.WHITE);
-            addView(mPromo);
-
-            mFadeAnimation = ObjectAnimator.ofFloat(mPromo, View.ALPHA, 1f);
-            mFadeAnimation.setDuration(FADE_DURATION_MS);
-            mFadeAnimation.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    mFadeAnimation = null;
-                    mPromo.setBackgroundResource(0);
-                    removeView(oldPromo);
-                }
-            });
-            mFadeAnimation.start();
-        } else {
-            removeView(oldPromo);
-            addView(mPromo);
-        }
-    }
-
-    private int getDesiredPromoType() {
-        if (!mModel.isSignedIn()) {
-            return PROMO_TYPE_SIGN_IN;
-        } else {
-            return mModel.isSyncEnabled() ? PROMO_TYPE_SYNC_ENABLED : PROMO_TYPE_SYNC_DISABLED;
-        }
-    }
-
-    private View createPromoView(int promoType) {
-        if (promoType == PROMO_TYPE_SIGN_IN) {
-            return createSignInPromoView();
-        } else {
-            return createSyncPromoView(promoType == PROMO_TYPE_SYNC_ENABLED);
-        }
-    }
-
-    private View createSyncPromoView(boolean isSyncEnabled) {
-        View syncPromoView = LayoutInflater.from(getContext()).inflate(
-                R.layout.recent_tabs_sync_promo, this, false);
-
-        TextView textView = (TextView) syncPromoView.findViewById(R.id.text_view);
-        View enableSyncButton = syncPromoView.findViewById(R.id.enable_sync_button);
-
-        if (isSyncEnabled) {
-            textView.setText(R.string.ntp_recent_tabs_sync_promo_instructions);
-            textView.setTextColor(TEXT_COLOR_LIGHT);
-            enableSyncButton.setVisibility(View.GONE);
-        } else {
-            textView.setText(R.string.ntp_recent_tabs_sync_enable_sync);
-            textView.setTextColor(TEXT_COLOR_NORMAL);
-            enableSyncButton.setOnClickListener(new OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    mModel.enableSync();
-                }
-            });
-        }
-
-        return syncPromoView;
-    }
-
-    private View createSignInPromoView() {
-        AccountSigninView signInPromoView = (AccountSigninView) LayoutInflater.from(getContext())
-                .inflate(R.layout.account_signin_view, this, false);
-        signInPromoView.init(mModel.getProfileDataCache());
-        signInPromoView.getLayoutParams().height = LayoutParams.WRAP_CONTENT;
-        ((FrameLayout.LayoutParams) signInPromoView.getLayoutParams()).gravity = Gravity.CENTER;
-        signInPromoView.configureForRecentTabsOrBookmarksPage();
-        signInPromoView.setListener(new AccountSigninView.Listener() {
-            @Override
-            public void onAccountSelectionCanceled() {
-                assert mUserActionListener != null;
-                mUserActionListener.onAccountSelectionCancelled();
-            }
-
-            @Override
-            public void onNewAccount() {
-                if (mUserActionListener != null) mUserActionListener.onNewAccount();
-
-                AccountAdder.getInstance().addAccount(mActivity, AccountAdder.ADD_ACCOUNT_RESULT);
-            }
-
-            @Override
-            public void onAccountSelected(String accountName, boolean settingsClicked) {
-                assert !settingsClicked : "Settings should be hidden in RecentTabsPromoView.";
-
-                if (mUserActionListener != null) mUserActionListener.onAccountSelectionConfirmed();
-                SigninManager.get(mActivity).signIn(accountName, mActivity, null);
-            }
-
-            @Override
-            public void onFailedToSetForcedAccount(String forcedAccountName) {
-                // TODO(bauerb): make sure we shouldn't see SignInPromoView.
-                assert false : "No forced accounts in SignInPromoView";
-            }
-        });
-        signInPromoView.setDelegate(new AccountSigninView.Delegate() {
-            @Override
-            public FragmentManager getFragmentManager() {
-                return mActivity.getFragmentManager();
-            }
-        });
-        SigninManager.logSigninStartAccessPoint(mModel.getAccessPoint());
-        return signInPromoView;
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsRowAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsRowAdapter.java
index a301e552..bad325df 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsRowAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsRowAdapter.java
@@ -27,8 +27,9 @@
 import org.chromium.chrome.browser.ntp.ForeignSessionHelper.ForeignSession;
 import org.chromium.chrome.browser.ntp.ForeignSessionHelper.ForeignSessionTab;
 import org.chromium.chrome.browser.ntp.ForeignSessionHelper.ForeignSessionWindow;
-import org.chromium.chrome.browser.ntp.RecentTabsPromoView.UserActionListener;
 import org.chromium.chrome.browser.ntp.RecentlyClosedBridge.RecentlyClosedTab;
+import org.chromium.chrome.browser.signin.SigninAccessPoint;
+import org.chromium.chrome.browser.signin.SigninAndSyncView;
 import org.chromium.ui.WindowOpenDisposition;
 import org.chromium.ui.base.DeviceFormFactor;
 
@@ -593,20 +594,16 @@
         View getChildView(int childPosition, boolean isLastChild, View convertView,
                 ViewGroup parent) {
             if (convertView == null) {
-                convertView = new RecentTabsPromoView(
-                        mActivity, mRecentTabsManager, new UserActionListener() {
-                            @Override
-                            public void onAccountSelectionConfirmed() {
-                                RecordUserAction.record("Signin_Signin_FromRecentTabs");
-                            }
-                            @Override
-                            public void onNewAccount() {}
-                            @Override
-                            public void onAccountSelectionCancelled() {
-                                mRecentTabsManager.setSigninPromoDeclined();
-                                notifyDataSetChanged();
-                            }
-                        });
+                SigninAndSyncView.Listener listener = new SigninAndSyncView.Listener() {
+                    @Override
+                    public void onViewDismissed() {
+                        mRecentTabsManager.setSigninPromoDeclined();
+                        notifyDataSetChanged();
+                    }
+                };
+
+                convertView =
+                        new SigninAndSyncView(mActivity, listener, SigninAccessPoint.RECENT_TABS);
             }
             if (!mRecentTabsManager.isSignedIn()) {
                 RecordUserAction.record("Signin_Impression_FromRecentTabs");
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
index 4da8bdc..061de45 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
@@ -6,6 +6,7 @@
 
 import android.os.AsyncTask;
 
+import org.chromium.base.Callback;
 import org.chromium.base.ObserverList;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.VisibleForTesting;
@@ -18,6 +19,7 @@
 import org.chromium.content_public.browser.WebContents;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -470,17 +472,32 @@
         nativeCheckMetadataConsistency(mNativeOfflinePageBridge);
     }
 
+    private static class CheckPagesExistOfflineCallbackInternal {
+        private Callback<Set<String>> mCallback;
+
+        CheckPagesExistOfflineCallbackInternal(Callback<Set<String>> callback) {
+            mCallback = callback;
+        }
+
+        @CalledByNative("CheckPagesExistOfflineCallbackInternal")
+        public void onResult(String[] results) {
+            Set<String> resultSet = new HashSet<>();
+            Collections.addAll(resultSet, results);
+            mCallback.onResult(resultSet);
+        }
+    }
+
     /**
-     * Gets the offline URL of an offline page of that is saved for the online URL.
-     * This method is deprecated. Use OfflinePageBridge#getPagesByOnlineUrl.
+     * Returns via callback any urls in <code>urls</code> for which there exist offline pages.
      *
-     * @param onlineUrl Online URL, which might have offline copy.
-     * @return URL pointing to the offline copy or <code>null</code> if none exists.
+     * TODO(http://crbug.com/598006): Add metrics for preventing UI jank.
      */
-    public boolean offlinePageExists(String onlineUrl) {
-        assert mIsNativeOfflinePageModelLoaded;
-        OfflinePageItem item = nativeGetPageByOnlineURL(mNativeOfflinePageBridge, onlineUrl);
-        return item != null;
+    public void checkPagesExistOffline(Set<String> urls, Callback<Set<String>> callback) {
+        String[] urlArray = urls.toArray(new String[urls.size()]);
+
+        CheckPagesExistOfflineCallbackInternal callbackInternal =
+                new CheckPagesExistOfflineCallbackInternal(callback);
+        nativeCheckPagesExistOffline(mNativeOfflinePageBridge, urlArray, callbackInternal);
     }
 
     private DeletePageCallback wrapCallbackWithHistogramReporting(
@@ -587,6 +604,8 @@
     @VisibleForTesting
     native void nativeGetAllPages(long nativeOfflinePageBridge, List<OfflinePageItem> offlinePages,
             final MultipleOfflinePageItemCallback callback);
+    private native void nativeCheckPagesExistOffline(long nativeOfflinePageBridge, Object[] urls,
+            CheckPagesExistOfflineCallbackInternal callback);
     native void nativeHasPages(
             long nativeOfflinePageBridge, String nameSpace, final HasPagesCallback callback);
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/MainPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/MainPreferences.java
index c582536..5514860 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/MainPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/MainPreferences.java
@@ -4,7 +4,6 @@
 
 package org.chromium.chrome.browser.preferences;
 
-import android.content.Intent;
 import android.os.Bundle;
 import android.os.Handler;
 import android.preference.Preference;
@@ -140,8 +139,8 @@
                 }
 
                 mSignInPreference.setEnabled(false);
-                SigninManager.logSigninStartAccessPoint(SigninAccessPoint.SETTINGS);
-                startActivity(new Intent(getActivity(), AccountSigninActivity.class));
+                AccountSigninActivity
+                        .startAccountSigninActivity(getActivity(), SigninAccessPoint.SETTINGS);
                 return true;
             }
         });
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountListAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountListAdapter.java
deleted file mode 100644
index bf8e5893..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountListAdapter.java
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.signin;
-
-import android.content.Context;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import org.chromium.chrome.R;
-import org.chromium.chrome.browser.firstrun.ProfileDataCache;
-
-/**
-* Adapter for AccountListView. It associates an array of account names on the device and
-* provides account views of these accounts.
-*/
-public class AccountListAdapter extends ArrayAdapter<String> {
-    private final LayoutInflater mInflater;
-    private final ProfileDataCache mProfileData;
-    private int mSelectedAccountPosition = 0;
-
-    public AccountListAdapter(Context context, ProfileDataCache profileData) {
-        super(context, 0);
-        mInflater = LayoutInflater.from(context);
-        mProfileData = profileData;
-    }
-
-    @Override
-    public View getView(int position, View convertView, ViewGroup parent) {
-        View view = convertView;
-        if (view == null) {
-            view = mInflater.inflate(R.layout.account_signin_account_view, parent, false);
-        }
-
-        // Sets account profile image, name and selection status.
-        String accountName = getItem(position);
-        ImageView accountImage = (ImageView) view.findViewById(R.id.account_image);
-        // The view at the last position is the "Add account" view.
-        if (position == getCount() - 1) {
-            accountImage.setImageResource(R.drawable.add_circle_blue);
-        } else {
-            accountImage.setImageBitmap(mProfileData.getImage(accountName));
-        }
-        ((TextView) view.findViewById(R.id.account_name)).setText(accountName);
-        if (position == mSelectedAccountPosition) {
-            view.findViewById(R.id.account_selection_mark).setVisibility(View.VISIBLE);
-        } else {
-            view.findViewById(R.id.account_selection_mark).setVisibility(View.GONE);
-        }
-
-        return view;
-    }
-
-    /**
-     * Sets selected account position.
-     * @param position Position in the collection of the associated items.
-     */
-    public void setSelectedAccountPosition(int position) {
-        mSelectedAccountPosition = position;
-    }
-
-    /**
-     * Gets selected account position.
-     */
-    public int getSelectedAccountPosition() {
-        return mSelectedAccountPosition;
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountListView.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountListView.java
deleted file mode 100644
index 1740da5c..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountListView.java
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.signin;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.widget.ListView;
-
-/**
-* ListView to list accounts on device.
-*/
-public class AccountListView extends ListView {
-    public AccountListView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    @Override
-    protected float getTopFadingEdgeStrength() {
-        // Disable fading out effect at the top of this ListView.
-        return 0;
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninActivity.java
index 7d44cb1..21acd8c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninActivity.java
@@ -4,8 +4,10 @@
 
 package org.chromium.chrome.browser.signin;
 
+import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
+import android.support.annotation.IntDef;
 import android.support.v7.app.AppCompatActivity;
 import android.view.LayoutInflater;
 
@@ -18,22 +20,40 @@
 import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
 import org.chromium.chrome.browser.preferences.PreferencesLauncher;
 import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.signin.SigninManager.SignInCallback;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 
 /**
  * An Activity displayed from the MainPreferences to allow the user to pick an account to
  * sign in to. The AccountSigninView.Delegate interface is fulfilled by the AppCompatActivity.
  */
 public class AccountSigninActivity extends AppCompatActivity
-        implements AccountSigninView.Listener, AccountSigninView.Delegate,
-                   SigninManager.SignInCallback{
-    private static final String TAG = "SigninActivity";
-
-    private static final String CONFIRM_IMPORT_SYNC_DATA_DIALOG_TAG =
-            "signin_import_data_tag";
+        implements AccountSigninView.Listener, AccountSigninView.Delegate {
+    private static final String TAG = "AccountSigninActivity";
+    private static final String INTENT_SIGNIN_ACCESS_POINT =
+            "AccountSigninActivity.SigninAccessPoint";
 
     private AccountSigninView mView;
-    private String mAccountName;
-    private boolean mShowSigninSettings = false;
+    private ProfileDataCache mProfileDataCache;
+
+    @IntDef({SigninAccessPoint.SETTINGS, SigninAccessPoint.BOOKMARK_MANAGER,
+        SigninAccessPoint.RECENT_TABS})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface AccessPoint {}
+    @AccessPoint private int mAccessPoint;
+
+    /**
+     * A convenience method to create a AccountSigninActivity passing the access point as an
+     * intent.
+     * @param accessPoint - A SigninAccessPoint designating where the activity is created from.
+     */
+    public static void startAccountSigninActivity(Context context, @AccessPoint int accessPoint) {
+        Intent intent = new Intent(context, AccountSigninActivity.class);
+        intent.putExtra(INTENT_SIGNIN_ACCESS_POINT, accessPoint);
+        context.startActivity(intent);
+    }
 
     @Override
     @SuppressFBWarnings("DM_EXIT")
@@ -52,52 +72,101 @@
         // We don't trust android to restore the saved state correctly, so pass null.
         super.onCreate(null);
 
+        mAccessPoint = getIntent().getIntExtra(INTENT_SIGNIN_ACCESS_POINT, -1);
+        assert mAccessPoint == SigninAccessPoint.BOOKMARK_MANAGER
+                || mAccessPoint == SigninAccessPoint.RECENT_TABS
+                || mAccessPoint == SigninAccessPoint.SETTINGS : "invalid access point";
+
+        if (savedInstanceState == null && getAccessPoint() == SigninAccessPoint.BOOKMARK_MANAGER) {
+            RecordUserAction.record("Stars_SignInPromoActivity_Launched");
+        }
+
         mView = (AccountSigninView) LayoutInflater.from(this).inflate(
                 R.layout.account_signin_view, null);
-        mView.init(new ProfileDataCache(this, Profile.getLastUsedProfile()));
+        mView.init(getProfileDataCache());
         mView.setListener(this);
         mView.setDelegate(this);
 
+        if (getAccessPoint() == SigninAccessPoint.BOOKMARK_MANAGER
+                || getAccessPoint() == SigninAccessPoint.RECENT_TABS) {
+            mView.configureForRecentTabsOrBookmarksPage();
+        }
+
+        SigninManager.logSigninStartAccessPoint(getAccessPoint());
+
         setContentView(mView);
     }
 
     @Override
+    public void onDestroy() {
+        super.onDestroy();
+
+        if (mProfileDataCache != null) {
+            mProfileDataCache.destroy();
+            mProfileDataCache = null;
+        }
+    }
+
+    private ProfileDataCache getProfileDataCache() {
+        if (mProfileDataCache == null) {
+            mProfileDataCache = new ProfileDataCache(this, Profile.getLastUsedProfile());
+        }
+        return mProfileDataCache;
+    }
+
+    @AccessPoint private int getAccessPoint() {
+        return mAccessPoint;
+    }
+
+    @Override
     public void onAccountSelectionCanceled() {
         finish();
     }
 
     @Override
     public void onNewAccount() {
+        if (getAccessPoint() == SigninAccessPoint.BOOKMARK_MANAGER) {
+            RecordUserAction.record("Stars_SignInPromoActivity_NewAccount");
+        }
+
         AccountAdder.getInstance().addAccount(this, AccountAdder.ADD_ACCOUNT_RESULT);
     }
 
     @Override
-    public void onAccountSelected(String accountName, boolean settingsClicked) {
-        mShowSigninSettings = settingsClicked;
-        mAccountName = accountName;
-        RecordUserAction.record("Signin_Signin_FromSettings");
-        SigninManager.get(this).signIn(accountName, this, this);
-    }
-
-    @Override
-    public void onFailedToSetForcedAccount(String forcedAccountName) {
-        assert false : "No forced accounts in account switching preferences.";
-
-    }
-
-    @Override
-    public void onSignInComplete() {
-        if (mShowSigninSettings) {
-            Intent intent = PreferencesLauncher.createIntentForSettingsPage(
-                    this, AccountManagementFragment.class.getName());
-            startActivity(intent);
+    public void onAccountSelected(final String accountName, final boolean settingsClicked) {
+        switch (getAccessPoint()) {
+            case SigninAccessPoint.BOOKMARK_MANAGER:
+                RecordUserAction.record("Stars_SignInPromoActivity_SignedIn");
+                RecordUserAction.record("Signin_Signin_FromBookmarkManager");
+                break;
+            case SigninAccessPoint.RECENT_TABS:
+                RecordUserAction.record("Signin_Signin_FromRecentTabs");
+                break;
+            case SigninAccessPoint.SETTINGS:
+                RecordUserAction.record("Signin_Signin_FromSettings");
+                break;
+            default:
         }
 
-        finish();
+        final Context context = this;
+        SigninManager.get(this).signIn(accountName, this, new SignInCallback(){
+
+            @Override
+            public void onSignInComplete() {
+                if (settingsClicked) {
+                    Intent intent = PreferencesLauncher.createIntentForSettingsPage(
+                            context, AccountManagementFragment.class.getName());
+                    startActivity(intent);
+                }
+
+                finish();
+            }
+
+            @Override
+            public void onSignInAborted() {}
+        });
     }
 
     @Override
-    public void onSignInAborted() {
-        assert false : "Signin cannot be aborted when forced.";
-    }
+    public void onFailedToSetForcedAccount(String forcedAccountName) {}
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninChooseView.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninChooseView.java
new file mode 100644
index 0000000..dc6f53f
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninChooseView.java
@@ -0,0 +1,181 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.signin;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.firstrun.ProfileDataCache;
+
+import java.util.List;
+
+/**
+* The view that allows the user to choose the sign in account.
+*/
+public class AccountSigninChooseView extends ScrollView {
+    private final LayoutInflater mInflater;
+    private LinearLayout mRootChildView;
+    private int mAccountViewStartIndex;
+    private int mSelectedAccountPosition;
+    private Observer mObserver;
+
+    /**
+    * Add new account observer.
+    */
+    public interface Observer {
+        /**
+        * On add new account clicked.
+        */
+        void onAddNewAccount();
+    }
+
+    public AccountSigninChooseView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mInflater = LayoutInflater.from(context);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mRootChildView =
+                (LinearLayout) findViewById(R.id.account_signin_choose_view_root_child_view);
+        mAccountViewStartIndex = mRootChildView.getChildCount();
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        // This assumes that view's layout_width and layout_height are set to match_parent.
+        assert MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY;
+        assert MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY;
+
+        int width = MeasureSpec.getSize(widthMeasureSpec);
+        int height = MeasureSpec.getSize(heightMeasureSpec);
+
+        View title = findViewById(R.id.signin_title);
+        ViewGroup.LayoutParams params = title.getLayoutParams();
+        if (height > width) {
+            // Sets the title aspect ratio to be 16:9.
+            params.height = width * 9 / 16;
+            title.setPadding(
+                    title.getPaddingLeft(), 0, title.getPaddingRight(), title.getPaddingBottom());
+        } else {
+            params.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+
+            // Adds top padding.
+            title.setPadding(title.getPaddingLeft(),
+                    getResources().getDimensionPixelOffset(R.dimen.signin_screen_top_padding),
+                    title.getPaddingRight(), title.getPaddingBottom());
+        }
+        title.setLayoutParams(params);
+
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+    }
+
+    @Override
+    protected float getTopFadingEdgeStrength() {
+        // Disable fading out effect at the top of this ScrollView.
+        return 0;
+    }
+
+    /**
+    * Updates candidate accounts to sign in.
+    *
+    * @param accounts The candidate accounts.
+    * @param accountToSelect The index of the default selected account to sign in.
+    * @param profileData The ProfileDataCache contains accounts' info.
+    */
+    public void updateAccounts(
+            List<String> accounts, int accountToSelect, ProfileDataCache profileData) {
+        mRootChildView.removeViews(
+                mAccountViewStartIndex, mRootChildView.getChildCount() - mAccountViewStartIndex);
+        if (accounts.isEmpty()) return;
+
+        // Add accounts view.
+        for (int i = 0; i < accounts.size(); i++) {
+            View view =
+                    mInflater.inflate(R.layout.account_signin_account_view, mRootChildView, false);
+
+            // Sets account profile image and name.
+            String accountName = accounts.get(i);
+            ((ImageView) view.findViewById(R.id.account_image))
+                    .setImageBitmap(profileData.getImage(accountName));
+            ((TextView) view.findViewById(R.id.account_name)).setText(accountName);
+
+            view.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    v.findViewById(R.id.account_selection_mark).setVisibility(View.VISIBLE);
+                    mRootChildView.getChildAt(mSelectedAccountPosition + mAccountViewStartIndex)
+                            .findViewById(R.id.account_selection_mark)
+                            .setVisibility(View.GONE);
+                    mSelectedAccountPosition =
+                            mRootChildView.indexOfChild(v) - mAccountViewStartIndex;
+                }
+            });
+
+            mRootChildView.addView(view);
+        }
+
+        // The view at the last position is the "Add account" view.
+        View view = mInflater.inflate(R.layout.account_signin_account_view, mRootChildView, false);
+        ((ImageView) view.findViewById(R.id.account_image))
+                .setImageResource(R.drawable.add_circle_blue);
+        ((TextView) view.findViewById(R.id.account_name))
+                .setText(getResources().getString(R.string.signin_add_account));
+        view.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if (mObserver != null) mObserver.onAddNewAccount();
+            }
+        });
+        mRootChildView.addView(view);
+
+        // Sets the default selected account selection status.
+        mRootChildView.getChildAt(accountToSelect + mAccountViewStartIndex)
+                .findViewById(R.id.account_selection_mark)
+                .setVisibility(View.VISIBLE);
+        mSelectedAccountPosition = accountToSelect;
+    }
+
+    /**
+    * Updates candidate accounts' profile image.
+    *
+    * @param profileData The ProfileDataCache contains accounts' profile image.
+    */
+    public void updateAccountProfileImages(ProfileDataCache profileData) {
+        // Do not update the last "Add account" view.
+        for (int i = mAccountViewStartIndex; i < mRootChildView.getChildCount() - 1; i++) {
+            View view = mRootChildView.getChildAt(i);
+            String accountEmail =
+                    ((TextView) view.findViewById(R.id.account_name)).getText().toString();
+            ((ImageView) view.findViewById(R.id.account_image))
+                    .setImageBitmap(profileData.getImage(accountEmail));
+        }
+    }
+
+    /**
+    * Sets add new account observer. See {@link Observer}
+    *
+    * @param observer The observer.
+    */
+    public void setAddNewAccountObserver(Observer observer) {
+        mObserver = observer;
+    }
+
+    /**
+     * Gets selected account position.
+     */
+    public int getSelectedAccountPosition() {
+        return mSelectedAccountPosition;
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninConfirmationView.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninConfirmationView.java
index 8ad1a51..ea87232 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninConfirmationView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninConfirmationView.java
@@ -6,6 +6,7 @@
 
 import android.content.Context;
 import android.util.AttributeSet;
+import android.view.View;
 import android.widget.LinearLayout;
 import android.widget.RelativeLayout;
 import android.widget.ScrollView;
@@ -42,15 +43,25 @@
         int width = MeasureSpec.getSize(widthMeasureSpec);
         int height = MeasureSpec.getSize(heightMeasureSpec);
 
-        // Sets aspect ratio of the head to 16:9.
+        View head = findViewById(R.id.signin_confirmation_head);
+        RelativeLayout.LayoutParams headLayoutParams =
+                (RelativeLayout.LayoutParams) head.getLayoutParams();
+        View accountImage = findViewById(R.id.signin_account_image);
+        LinearLayout.LayoutParams accountImageLayoutParams =
+                (LinearLayout.LayoutParams) accountImage.getLayoutParams();
         if (height > width) {
-            LinearLayout layout = (LinearLayout) findViewById(R.id.signin_confirmation_head);
-            RelativeLayout.LayoutParams params =
-                    (RelativeLayout.LayoutParams) layout.getLayoutParams();
-            params.height = width * 9 / 16;
-            params.width = LayoutParams.MATCH_PARENT;
-            layout.setLayoutParams(params);
+            // Sets aspect ratio of the head to 16:9.
+            headLayoutParams.height = width * 9 / 16;
+            accountImageLayoutParams.topMargin = 0;
+        } else {
+            headLayoutParams.height = LayoutParams.WRAP_CONTENT;
+
+            // Adds top margin.
+            accountImageLayoutParams.topMargin =
+                    getResources().getDimensionPixelOffset(R.dimen.signin_screen_top_padding);
         }
+        head.setLayoutParams(headLayoutParams);
+        accountImage.setLayoutParams(accountImageLayoutParams);
 
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninView.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninView.java
index d8f70472..8b5c902 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninView.java
@@ -10,14 +10,10 @@
 import android.text.TextUtils;
 import android.text.method.LinkMovementMethod;
 import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
 import android.view.View;
-import android.widget.AdapterView;
 import android.widget.Button;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
-import android.widget.ListView;
 import android.widget.TextView;
 
 import org.chromium.base.ApiCompatibilityUtils;
@@ -39,7 +35,6 @@
 
 import java.util.List;
 
-// TODO(gogerald): add landscape mode (http://crbug.com/599139).
 // TODO(gogerald): refactor common part into one place after redesign all sign in screens.
 
 /**
@@ -49,8 +44,7 @@
  * {@link AccountSigninView#setDelegate(Delegate)} after the view has been inflated.
  */
 
-public class AccountSigninView
-        extends FrameLayout implements AdapterView.OnItemClickListener, ProfileDownloader.Observer {
+public class AccountSigninView extends FrameLayout implements ProfileDownloader.Observer {
     /**
      * Callbacks for various account selection events.
      */
@@ -99,12 +93,9 @@
 
     private AccountManagerHelper mAccountManagerHelper;
     private List<String> mAccountNames;
-    private View mSigninView;
-    private AccountListAdapter mAccountListAdapter;
-    private ListView mAccountListView;
+    private AccountSigninChooseView mSigninChooseView;
     private ButtonCompat mPositiveButton;
     private Button mNegativeButton;
-    private TextView mTitle;
     private Listener mListener;
     private Delegate mDelegate;
     private String mForcedAccountName;
@@ -112,7 +103,6 @@
     private boolean mSignedIn;
     private int mCancelButtonTextId;
     private boolean mIsChildAccount;
-    private boolean mShowSettingsSpan = true;
 
     private AccountSigninConfirmationView mSigninConfirmationView;
     private ImageView mSigninAccountImage;
@@ -132,8 +122,6 @@
     public void init(ProfileDataCache profileData) {
         mProfileData = profileData;
         mProfileData.setObserver(this);
-        mAccountListAdapter = new AccountListAdapter(getContext(), profileData);
-        mAccountListView.setAdapter(mAccountListAdapter);
         showSigninPage();
     }
 
@@ -141,41 +129,12 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
 
-        mSigninView = findViewById(R.id.signin_choose_account_view);
-
-        mTitle = (TextView) findViewById(R.id.signin_title);
-
-        mAccountListView = (ListView) findViewById(R.id.signin_account_list);
-        mAccountListView.setOnItemClickListener(this);
-        View signinChoiceDescription =
-                LayoutInflater.from(getContext())
-                        .inflate(R.layout.account_signin_choice_description_view, null, false);
-        signinChoiceDescription.setOnClickListener(null);
-        mAccountListView.addHeaderView(signinChoiceDescription);
-
-        // Once the user has touched this ListView, prevent the parent view from handling touch
-        // events. This allows the ListView to behave reasonably when nested inside a ListView.
-        // TODO(gogerald): Remove this listener after https://crbug.com/583774 has been fixed.
-        mAccountListView.setOnTouchListener(new ListView.OnTouchListener() {
+        mSigninChooseView = (AccountSigninChooseView) findViewById(R.id.account_signin_choose_view);
+        mSigninChooseView.setAddNewAccountObserver(new AccountSigninChooseView.Observer() {
             @Override
-            public boolean onTouch(View view, MotionEvent event) {
-                int action = event.getAction();
-                switch (action) {
-                    case MotionEvent.ACTION_DOWN:
-                        view.getParent().requestDisallowInterceptTouchEvent(true);
-                        break;
-
-                    case MotionEvent.ACTION_UP:
-                        view.performClick();
-                        view.getParent().requestDisallowInterceptTouchEvent(false);
-                        break;
-                    default:
-                        // Ignore.
-                        break;
-                }
-
-                view.onTouchEvent(event);
-                return true;
+            public void onAddNewAccount() {
+                mListener.onNewAccount();
+                RecordUserAction.record("Signin_AddAccountToDevice");
             }
         });
 
@@ -210,23 +169,6 @@
     }
 
     @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        // This assumes that view's layout_width and layout_height are set to match_parent.
-        assert MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY;
-        assert MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY;
-
-        int width = MeasureSpec.getSize(widthMeasureSpec);
-        int height = MeasureSpec.getSize(heightMeasureSpec);
-
-        // Sets title aspect ratio to be 16:9.
-        if (height > width) {
-            mTitle.setHeight(width * 9 / 16);
-        }
-
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-    }
-
-    @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         updateAccounts();
@@ -251,8 +193,6 @@
      * This is currently used in the Recent Tabs Promo and the bookmarks page.
      */
     public void configureForRecentTabsOrBookmarksPage() {
-        mShowSettingsSpan = false;
-
         setBackgroundResource(R.color.ntp_bg);
         mCancelButtonTextId = R.string.cancel;
         setUpCancelButton();
@@ -303,24 +243,18 @@
                 return false;
             }
         } else {
-            accountToSelect = getIndexOfNewElement(oldAccountNames, mAccountNames,
-                    mAccountListAdapter.getSelectedAccountPosition());
+            accountToSelect = getIndexOfNewElement(
+                    oldAccountNames, mAccountNames, mSigninChooseView.getSelectedAccountPosition());
         }
 
-        mAccountListAdapter.clear();
+        mSigninChooseView.updateAccounts(mAccountNames, accountToSelect, mProfileData);
         if (!mAccountNames.isEmpty()) {
-            mAccountListAdapter.addAll(mAccountNames);
-            mAccountListAdapter.add(getResources().getString(R.string.signin_add_account));
-
             setUpSigninButton(true);
         } else {
             setUpSigninButton(false);
         }
 
         mProfileData.update();
-        updateProfileImages();
-
-        selectAccount(accountToSelect);
 
         return oldAccountNames != null
                 && !(oldAccountNames.size() == mAccountNames.size()
@@ -352,13 +286,7 @@
     @Override
     public void onProfileDownloaded(String accountId, String fullName, String givenName,
             Bitmap bitmap) {
-        updateProfileImages();
-    }
-
-    private void updateProfileImages() {
-        if (mProfileData == null) return;
-
-        mAccountListAdapter.notifyDataSetChanged();
+        mSigninChooseView.updateAccountProfileImages(mProfileData);
 
         if (mSignedIn) updateSignedInAccountInfo();
     }
@@ -389,7 +317,7 @@
         mSignedIn = false;
 
         mSigninConfirmationView.setVisibility(View.GONE);
-        mSigninView.setVisibility(View.VISIBLE);
+        mSigninChooseView.setVisibility(View.VISIBLE);
 
         setUpCancelButton();
         updateAccounts();
@@ -400,7 +328,7 @@
 
         updateSignedInAccountInfo();
 
-        mSigninView.setVisibility(View.GONE);
+        mSigninChooseView.setVisibility(View.GONE);
         mSigninConfirmationView.setVisibility(View.VISIBLE);
 
         setButtonsEnabled(true);
@@ -408,22 +336,15 @@
         setPositiveButtonDisabled();
         setUpUndoButton();
 
-        if (mShowSettingsSpan) {
-            NoUnderlineClickableSpan settingsSpan = new NoUnderlineClickableSpan() {
-                @Override
-                public void onClick(View widget) {
-                    mListener.onAccountSelected(getSelectedAccountName(), true);
-                }
-            };
-            mSigninSettingsControl.setText(
-                    SpanApplier.applySpans(getSettingsControlDescription(mIsChildAccount),
-                            new SpanInfo(SETTINGS_LINK_OPEN, SETTINGS_LINK_CLOSE, settingsSpan)));
-        } else {
-            // If we aren't showing the span, get rid of the LINK1 annotations.
-            mSigninSettingsControl.setText(getSettingsControlDescription(mIsChildAccount)
-                                                   .replace(SETTINGS_LINK_OPEN, "")
-                                                   .replace(SETTINGS_LINK_CLOSE, ""));
-        }
+        NoUnderlineClickableSpan settingsSpan = new NoUnderlineClickableSpan() {
+            @Override
+            public void onClick(View widget) {
+                mListener.onAccountSelected(getSelectedAccountName(), true);
+            }
+        };
+        mSigninSettingsControl.setText(
+                SpanApplier.applySpans(getSettingsControlDescription(mIsChildAccount),
+                        new SpanInfo(SETTINGS_LINK_OPEN, SETTINGS_LINK_CLOSE, settingsSpan)));
     }
 
     private void showConfirmSigninPageAccountTrackerServiceCheck() {
@@ -592,23 +513,6 @@
         return mForcedAccountName != null;
     }
 
-    // Overrides AdapterView.OnItemClickListener.
-    @Override
-    public void onItemClick(AdapterView<?> adapter, View view, int position, long id) {
-        int positionInAccountListAdapter = position - mAccountListView.getHeaderViewsCount();
-        if (positionInAccountListAdapter == mAccountListAdapter.getCount() - 1) {
-            mListener.onNewAccount();
-            RecordUserAction.record("Signin_AddAccountToDevice");
-        } else {
-            selectAccount(positionInAccountListAdapter);
-        }
-    }
-
-    private void selectAccount(int position) {
-        mAccountListAdapter.setSelectedAccountPosition(position);
-        mAccountListAdapter.notifyDataSetChanged();
-    }
-
     private void setPositiveButtonEnabled() {
         mPositiveButton.setButtonColor(
                 ApiCompatibilityUtils.getColor(getResources(), R.color.light_active_color));
@@ -628,6 +532,6 @@
     }
 
     private String getSelectedAccountName() {
-        return mAccountNames.get(mAccountListAdapter.getSelectedAccountPosition());
+        return mAccountNames.get(mSigninChooseView.getSelectedAccountPosition());
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninAndSyncView.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninAndSyncView.java
new file mode 100644
index 0000000..65cb6e9d
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninAndSyncView.java
@@ -0,0 +1,265 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.signin;
+
+import android.content.Context;
+import android.content.Intent;
+import android.provider.Settings;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.Button;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.preferences.PreferencesLauncher;
+import org.chromium.chrome.browser.signin.AccountSigninActivity.AccessPoint;
+import org.chromium.chrome.browser.signin.SigninManager.SignInStateObserver;
+import org.chromium.chrome.browser.sync.ui.SyncCustomizationFragment;
+import org.chromium.sync.AndroidSyncSettings;
+import org.chromium.sync.AndroidSyncSettings.AndroidSyncSettingsObserver;
+import org.chromium.sync.signin.ChromeSigninController;
+
+/**
+ * A View that shows the user the next step they must complete to start syncing their data (eg.
+ * Recent Tabs or Bookmarks). For example, if the user is not signed in, the View will prompt them
+ * to do so and link to the AccountSigninActivity.
+ */
+public class SigninAndSyncView extends FrameLayout
+        implements AndroidSyncSettingsObserver, SignInStateObserver {
+    private static final String TAG = "SigninAndSyncView";
+    private final Listener mListener;
+    private final int mAccessPoint;
+    @AccessPoint private final SigninManager mSigninManager;
+
+    private final TextView mTitle;
+    private final TextView mDescription;
+    private final Button mNegativeButton;
+    private final Button mPositiveButton;
+
+    /**
+     * A listener for the container of the SigninAndSyncView to be informed of certain user
+     * interactions.
+     */
+    public interface Listener {
+        /**
+         * The user has pressed 'no thanks' and expects the view to be removed from its parent.
+         */
+        public void onViewDismissed();
+    }
+
+    /**
+     * Constructor for use from Java.
+     */
+    public SigninAndSyncView(Context context, Listener listener, @AccessPoint int accessPoint) {
+        // TODO(peconn): Simplify BookmarkPromoHeader
+        super(context);
+        mListener = listener;
+        mAccessPoint = accessPoint;
+
+        assert mAccessPoint == SigninAccessPoint.BOOKMARK_MANAGER
+                || mAccessPoint == SigninAccessPoint.RECENT_TABS
+                : "SigninAndSyncView only has strings for bookmark manager and recent tabs.";
+
+        mSigninManager = SigninManager.get(getContext());
+
+        addView(LayoutInflater.from(getContext())
+                .inflate(R.layout.signin_and_sync_view, this, false));
+
+        mTitle = (TextView) findViewById(R.id.title);
+        mDescription = (TextView) findViewById(R.id.description);
+        mNegativeButton = (Button) findViewById(R.id.no_thanks);
+        mPositiveButton = (Button) findViewById(R.id.sign_in);
+
+        // The title stays the same no matter what action the user must take.
+        if (mAccessPoint == SigninAccessPoint.BOOKMARK_MANAGER) {
+            mTitle.setText(R.string.sync_your_bookmarks);
+        } else {
+            mTitle.setVisibility(View.GONE);
+        }
+
+        // We don't need to call update() here as it will be called in onAttachedToWindow().
+    }
+
+    private void update() {
+        ViewState viewState;
+        if (!ChromeSigninController.get(getContext()).isSignedIn()) {
+            viewState = getStateForSignin();
+        } else if (!AndroidSyncSettings.isMasterSyncEnabled(getContext())) {
+            viewState = getStateForEnableAndroidSync();
+        } else if (!AndroidSyncSettings.isChromeSyncEnabled(getContext())) {
+            viewState = getStateForEnableChromeSync();
+        } else {
+            viewState = getStateForStartUsing();
+        }
+        viewState.apply(mDescription, mPositiveButton, mNegativeButton);
+    }
+
+    /**
+     * The ViewState class represents all the UI elements that can change for each variation of
+     * this View. We use this to ensure each variation (created in the getStateFor* methods)
+     * explicitly touches each UI element.
+     */
+    private static class ViewState {
+        private final int mDescriptionText;
+        private final ButtonState mPositiveButtonState;
+        private final ButtonState mNegativeButtonState;
+
+        public ViewState(int mDescriptionText,
+                ButtonState mPositiveButtonState, ButtonState mNegativeButtonState) {
+            this.mDescriptionText = mDescriptionText;
+            this.mPositiveButtonState = mPositiveButtonState;
+            this.mNegativeButtonState = mNegativeButtonState;
+        }
+
+        public void apply(TextView description, Button positiveButton, Button negativeButton) {
+            description.setText(mDescriptionText);
+            mNegativeButtonState.apply(negativeButton);
+            mPositiveButtonState.apply(positiveButton);
+        }
+    }
+
+    /**
+     * Classes to represent the state of a button that we are interested in, used to keep ViewState
+     * tidy and provide some convenience methods.
+     */
+    private abstract static class ButtonState {
+        public abstract void apply(Button button);
+    }
+
+    private static class ButtonAbsent extends ButtonState {
+        @Override
+        public void apply(Button button) {
+            button.setVisibility(View.GONE);
+        }
+    }
+
+    private static class ButtonPresent extends ButtonState {
+        private final int mTextResource;
+        private final OnClickListener mOnClickListener;
+
+        public ButtonPresent(int textResource, OnClickListener onClickListener) {
+            mTextResource = textResource;
+            mOnClickListener = onClickListener;
+        }
+
+        @Override
+        public void apply(Button button) {
+            button.setVisibility(View.VISIBLE);
+            button.setText(mTextResource);
+            button.setOnClickListener(mOnClickListener);
+        }
+    }
+
+    private ViewState getStateForSignin() {
+        int descId = mAccessPoint == SigninAccessPoint.BOOKMARK_MANAGER
+                ? R.string.bookmark_sign_in_promo_description
+                : R.string.recent_tabs_sign_in_promo_description;
+
+        ButtonState positiveButton = new ButtonPresent(
+                R.string.sign_in_button,
+                new OnClickListener() {
+                    @Override
+                    public void onClick(View view) {
+                        AccountSigninActivity
+                                .startAccountSigninActivity(getContext(), mAccessPoint);
+                    }
+                });
+
+        ButtonState negativeButton;
+        if (mAccessPoint == SigninAccessPoint.RECENT_TABS) {
+            negativeButton = new ButtonAbsent();
+        } else {
+            negativeButton = new ButtonPresent(R.string.no_thanks, new OnClickListener() {
+                @Override
+                public void onClick(View view) {
+                    mListener.onViewDismissed();
+                }
+            });
+        }
+
+        return new ViewState(descId, positiveButton, negativeButton);
+    }
+
+    private ViewState getStateForEnableAndroidSync() {
+        assert mAccessPoint == SigninAccessPoint.RECENT_TABS
+                : "Enable Android Sync should not be showing from bookmarks";
+
+        int descId = R.string.recent_tabs_sync_promo_enable_android_sync;
+
+        ButtonState positiveButton = new ButtonPresent(
+                R.string.open_settings_button,
+                new OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+                        // TODO(crbug.com/557784): Like AccountManagementFragment, this would also
+                        // benefit from going directly to an account.
+                        Intent intent = new Intent(Settings.ACTION_SYNC_SETTINGS);
+                        intent.putExtra(Settings.EXTRA_ACCOUNT_TYPES, new String[] {"com.google"});
+                        getContext().startActivity(intent);
+                    }
+                });
+
+        return new ViewState(descId, positiveButton, new ButtonAbsent());
+    }
+
+    private ViewState getStateForEnableChromeSync() {
+        int descId = mAccessPoint == SigninAccessPoint.BOOKMARK_MANAGER
+                ? R.string.bookmarks_sync_promo_enable_sync
+                : R.string.recent_tabs_sync_promo_enable_chrome_sync;
+
+        ButtonState positiveButton = new ButtonPresent(
+                R.string.enable_sync_button,
+                new OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+                        PreferencesLauncher.launchSettingsPage(getContext(),
+                                SyncCustomizationFragment.class.getName());
+                    }
+                });
+
+        return new ViewState(descId, positiveButton, new ButtonAbsent());
+    }
+
+    private ViewState getStateForStartUsing() {
+        assert mAccessPoint == SigninAccessPoint.RECENT_TABS
+                : "This should not be showing from bookmarks";
+
+        return new ViewState(R.string.ntp_recent_tabs_sync_promo_instructions,
+                new ButtonAbsent(), new ButtonAbsent());
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        mSigninManager.addSignInStateObserver(this);
+        AndroidSyncSettings.registerObserver(getContext(), this);
+        update();
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        mSigninManager.removeSignInStateObserver(this);
+        AndroidSyncSettings.unregisterObserver(getContext(), this);
+    }
+
+    // SigninStateObserver
+    @Override
+    public void onSignedIn() {
+        update();
+    }
+
+    @Override
+    public void onSignedOut() {
+        update();
+    }
+
+    // AndroidSyncStateObserver
+    @Override
+    public void androidSyncSettingsChanged() {
+        update();
+    }
+}
\ No newline at end of file
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index d6020c75..0e08bc2 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -988,8 +988,39 @@
       <message name="IDS_SIGNOUT_DIALOG_POSITIVE_BUTTON" desc="Button to sign out of Chrome">
         Sign out
       </message>
+      <message name="IDS_SIGN_IN_BUTTON" desc="Label for a button to sign in">
+        Sign in
+      </message>
 
       <!-- Sync strings -->
+      <message name="IDS_SYNC_YOUR_BOOKMARKS" desc="Title for the prompt to signin and enable sync to sync their bookmarks">
+        Sync your bookmarks
+      </message>
+      <message name="IDS_BOOKMARK_SIGN_IN_PROMO_DESCRIPTION" desc="Description for bookmark UI sign-in promotion.">
+        To get your bookmarks on all your devices, sign in to Chrome
+      </message>
+      <message name="IDS_RECENT_TABS_SIGN_IN_PROMO_DESCRIPTION" desc="Description for recent tabs UI sign-in promotion.">
+        To get your tabs from all your devices, sign in to Chrome
+      </message>
+      <message name="IDS_ENABLE_SYNC_BUTTON" desc="Text that displayed or button that allows the user to open Chrome settings to enable sync.">
+        Open settings
+      </message>
+      <message name="IDS_OPEN_SETTINGS_BUTTON" desc="Text that displayed or button that allows the open Android settings to enable sync.">
+        Open settings
+      </message>
+      <message name="IDS_BOOKMARKS_SYNC_PROMO_ENABLE_SYNC" desc="Text that displayed in a textview encouraging the user to enable sync.">
+        Bookmarks saved on your other devices will appear here
+      </message>
+      <message name="IDS_RECENT_TABS_SYNC_PROMO_ENABLE_CHROME_SYNC" desc="Text that displayed in a textview encouraging the user to enable sync.">
+        To get your tabs from all your devices, turn on sync
+      </message>
+      <message name="IDS_RECENT_TABS_SYNC_PROMO_ENABLE_ANDROID_SYNC" desc="Text that displayed in a textview encouraging the user to enable sync in the android settings.">
+        To get your tabs from all your devices, turn on "Auto-sync data" in Android account setting
+      </message>
+      <message name="IDS_NTP_RECENT_TABS_SYNC_PROMO_INSTRUCTIONS" desc="Information about sync displayed on the NTP when the user has signed in on mobile but not on desktop">
+        Tabs that you've opened in Chrome on your other devices will appear here
+      </message>
+      
       <message name="IDS_SIGN_IN_SYNC" desc="Sync preference title in signed-in prefs and prefix for notification related to sync [CHAR-LIMIT=32]">
         Sync
       </message>
@@ -1790,17 +1821,6 @@
       <message name="IDS_NTP_RECENT_TABS_SYNC_PROMO_TITLE" desc="Header for the promo explaining how users can see the list of tabs open on their other devices">
         Other devices
       </message>
-      <message name="IDS_NTP_RECENT_TABS_SYNC_PROMO_INSTRUCTIONS" desc="Information about sync displayed on the NTP when the user has signed in on mobile but not on desktop">
-        Access the tabs you have open on your computer, right here.
-
-Just open Chrome on your computer, go to the menu, and select “Sign in to Chrome…”
-      </message>
-      <message name="IDS_NTP_RECENT_TABS_SYNC_ENABLE_SYNC" desc="Text that displayed in a textview encouraging the user to enable sync.">
-        Tabs you have opened in Chrome on your other devices will appear here.
-      </message>
-      <message name="IDS_NTP_RECENT_TABS_SYNC_ENABLE_SYNC_BUTTON" desc="Text that displayed or button that allows the user to enable sync.">
-        Enable sync
-      </message>
       <message name="IDS_NTP_RECENT_TABS_LAST_SYNCED" desc="Label for the time since a device was last synced">
         Last synced: <ph name="WHEN">%1$s<ex>4 hours ago</ex></ph>
       </message>
@@ -1912,18 +1932,6 @@
       <message name="IDS_BOOKMARKS_FOLDER_EMPTY" desc="Text explaining that the currently selected bookmarks folder is empty.">
         No bookmarks here
       </message>
-      <message name="IDS_BOOKMARK_SIGN_IN_PROMO_TITLE" desc="Promo title encouraging the user to sign in to Chrome to improve their bookmarks experience. It means that after signing-in, bookmarks will become synced across devices and possible to search.">
-        Sync your bookmarks
-      </message>
-      <message name="IDS_BOOKMARK_SIGN_IN_PROMO_DESCRIPTION" desc="Description for bookmark UI sign-in promotion.">
-        To get your bookmarks on all your devices, sign in to Chrome
-      </message>
-      <message name="IDS_BOOKMARK_SIGN_IN_PROMO_NO_THANKS" desc="Text for the decline button in the bookmark UI">
-        No, thanks
-      </message>
-      <message name="IDS_BOOKMARK_SIGN_IN_PROMO_SIGN_IN" desc="Text for the sign-in button in promotion in the bookmark UI">
-        Sign in
-      </message>
       <message name="IDS_BOOKMARK_PAGE_SAVED" desc="Message shown after user adds a new bookmark. [CHAR-LIMIT=32]">
         Bookmarked
       </message>
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 5b6184ac..2b230931 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -110,7 +110,6 @@
   "java/src/org/chromium/chrome/browser/bookmarks/BookmarkRow.java",
   "java/src/org/chromium/chrome/browser/bookmarks/BookmarkSearchRow.java",
   "java/src/org/chromium/chrome/browser/bookmarks/BookmarkSearchView.java",
-  "java/src/org/chromium/chrome/browser/bookmarks/BookmarkSigninActivity.java",
   "java/src/org/chromium/chrome/browser/bookmarks/BookmarkUIObserver.java",
   "java/src/org/chromium/chrome/browser/bookmarks/BookmarkUIState.java",
   "java/src/org/chromium/chrome/browser/bookmarks/BookmarkUndoController.java",
@@ -500,7 +499,6 @@
   "java/src/org/chromium/chrome/browser/ntp/RecentTabsGroupView.java",
   "java/src/org/chromium/chrome/browser/ntp/RecentTabsManager.java",
   "java/src/org/chromium/chrome/browser/ntp/RecentTabsPage.java",
-  "java/src/org/chromium/chrome/browser/ntp/RecentTabsPromoView.java",
   "java/src/org/chromium/chrome/browser/ntp/RecentTabsRowAdapter.java",
   "java/src/org/chromium/chrome/browser/ntp/RecentlyClosedBridge.java",
   "java/src/org/chromium/chrome/browser/ntp/interests/InterestsItemView.java",
@@ -727,9 +725,8 @@
   "java/src/org/chromium/chrome/browser/signin/AccountIdProvider.java",
   "java/src/org/chromium/chrome/browser/signin/AccountManagementFragment.java",
   "java/src/org/chromium/chrome/browser/signin/AccountManagementScreenHelper.java",
-  "java/src/org/chromium/chrome/browser/signin/AccountListAdapter.java",
-  "java/src/org/chromium/chrome/browser/signin/AccountListView.java",
   "java/src/org/chromium/chrome/browser/signin/AccountSigninActivity.java",
+  "java/src/org/chromium/chrome/browser/signin/AccountSigninChooseView.java",
   "java/src/org/chromium/chrome/browser/signin/AccountSigninConfirmationView.java",
   "java/src/org/chromium/chrome/browser/signin/AccountSigninView.java",
   "java/src/org/chromium/chrome/browser/signin/AccountTrackerService.java",
@@ -738,6 +735,7 @@
   "java/src/org/chromium/chrome/browser/signin/GoogleActivityController.java",
   "java/src/org/chromium/chrome/browser/signin/OAuth2TokenService.java",
   "java/src/org/chromium/chrome/browser/signin/SignOutDialogFragment.java",
+  "java/src/org/chromium/chrome/browser/signin/SigninAndSyncView.java",
   "java/src/org/chromium/chrome/browser/signin/SigninHelper.java",
   "java/src/org/chromium/chrome/browser/signin/SigninInvestigator.java",
   "java/src/org/chromium/chrome/browser/signin/SigninManager.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/feedback/ConnectivityTaskTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/feedback/ConnectivityTaskTest.java
index e6252a17d..a922307 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/feedback/ConnectivityTaskTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/feedback/ConnectivityTaskTest.java
@@ -113,7 +113,7 @@
     @MediumTest
     @Feature({"Feedback"})
     public void testCallbackTwoTimeouts() throws InterruptedException {
-        final int checkTimeoutMs = 100;
+        final int checkTimeoutMs = 1000;
         final Semaphore semaphore = new Semaphore(0);
         final AtomicReference<FeedbackData> feedbackRef = new AtomicReference<>();
         final ConnectivityTask.ConnectivityResult callback =
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java
index 6a07108..22924a8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java
@@ -8,6 +8,7 @@
 import android.os.Environment;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import org.chromium.base.Callback;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.chrome.browser.ChromeActivity;
@@ -23,7 +24,9 @@
 import org.chromium.net.test.EmbeddedTestServer;
 
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -154,18 +157,6 @@
                 getPageByClientId(BOOKMARK_ID));
     }
 
-    @SmallTest
-    public void testOfflinePageExists() throws Exception {
-        loadUrl(mTestPage);
-        assertFalse("We should not say a page exists for one we haven't saved.",
-                mOfflinePageBridge.offlinePageExists(mTestPage));
-        savePage(SavePageResult.SUCCESS, mTestPage);
-        assertTrue("We should say a page exists for one we just saved.",
-                mOfflinePageBridge.offlinePageExists(mTestPage));
-        assertFalse("We should not say a page exists for one we haven't saved.",
-                mOfflinePageBridge.offlinePageExists(mTestPage + "?foo=bar"));
-    }
-
     @CommandLineFlags.Add("disable-features=OfflinePagesBackgroundLoading")
     @SmallTest
     public void testBackgroundLoadSwitch() throws Exception {
@@ -178,6 +169,26 @@
         });
     }
 
+    @SmallTest
+    public void testCheckPagesExistOffline() throws Exception {
+        // If we save a page, then it should exist in the result.
+        loadUrl(mTestPage);
+        savePage(SavePageResult.SUCCESS, mTestPage);
+        Set<String> testCases = new HashSet<>();
+        testCases.add(mTestPage);
+
+        // Querying for a page that hasn't been saved should not affect the result.
+        testCases.add(mTestPage + "?foo=bar");
+
+        Set<String> pages = checkPagesExistOffline(testCases);
+
+        assertEquals(
+                "We only saved one page and queried for it, so the result should be one string.", 1,
+                pages.size());
+        assertTrue("The only page returned should be the page that was actually saved.",
+                pages.contains(mTestPage));
+    }
+
     private void savePage(final int expectedResult, final String expectedUrl)
             throws InterruptedException {
         final Semaphore semaphore = new Semaphore(0);
@@ -185,7 +196,7 @@
             @Override
             public void run() {
                 assertNotNull("Tab is null", getActivity().getActivityTab());
-                assertEquals("URL does not match requested.", mTestPage,
+                assertEquals("URL does not match requested.", expectedUrl,
                         getActivity().getActivityTab().getUrl());
                 assertNotNull("WebContents is null",
                         getActivity().getActivityTab().getWebContents());
@@ -276,4 +287,24 @@
         assertTrue(semaphore.tryAcquire(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         return result[0];
     }
+
+    private Set<String> checkPagesExistOffline(final Set<String> query)
+            throws InterruptedException {
+        final Set<String> result = new HashSet<>();
+        final Semaphore semaphore = new Semaphore(0);
+        ThreadUtils.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mOfflinePageBridge.checkPagesExistOffline(query, new Callback<Set<String>>() {
+                    @Override
+                    public void onResult(Set<String> offlinedPages) {
+                        result.addAll(offlinedPages);
+                        semaphore.release();
+                    }
+                });
+            }
+        });
+        assertTrue(semaphore.tryAcquire(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        return result;
+    }
 }
diff --git a/chrome/browser/android/ntp/most_visited_sites.cc b/chrome/browser/android/ntp/most_visited_sites.cc
index 7b1de89..3f5e907 100644
--- a/chrome/browser/android/ntp/most_visited_sites.cc
+++ b/chrome/browser/android/ntp/most_visited_sites.cc
@@ -19,6 +19,7 @@
 #include "chrome/browser/history/top_sites_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search/suggestions/suggestions_service_factory.h"
+#include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/supervised_user/supervised_user_service.h"
 #include "chrome/browser/supervised_user/supervised_user_service_factory.h"
 #include "chrome/browser/supervised_user/supervised_user_url_filter.h"
@@ -203,7 +204,9 @@
   if (ShouldShowPopularSites() &&
       NeedPopularSites(profile_->GetPrefs(), num_sites_)) {
     popular_sites_.reset(new PopularSites(
-        profile_,
+        profile_->GetPrefs(),
+        TemplateURLServiceFactory::GetForProfile(profile_),
+        profile_->GetRequestContext(),
         GetPopularSitesCountry(),
         GetPopularSitesVersion(),
         false,
diff --git a/chrome/browser/android/ntp/popular_sites.cc b/chrome/browser/android/ntp/popular_sites.cc
index be7e3e4..13ee926 100644
--- a/chrome/browser/android/ntp/popular_sites.cc
+++ b/chrome/browser/android/ntp/popular_sites.cc
@@ -18,8 +18,6 @@
 #include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
 #include "components/google/core/browser/google_util.h"
@@ -48,17 +46,14 @@
 
 // Extract the country from the default search engine if the default search
 // engine is Google.
-std::string GetDefaultSearchEngineCountryCode(Profile* profile) {
-  DCHECK(profile);
+std::string GetDefaultSearchEngineCountryCode(
+    const TemplateURLService* template_url_service) {
+  DCHECK(template_url_service);
 
   base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
   if (!cmd_line->HasSwitch(switches::kEnableNTPSearchEngineCountryDetection))
     return std::string();
 
-  const TemplateURLService* template_url_service =
-      TemplateURLServiceFactory::GetForProfile(profile);
-  DCHECK(template_url_service);
-
   const TemplateURL* default_provider =
       template_url_service->GetDefaultSearchProvider();
   // It's possible to not have a default provider in the case that the default
@@ -93,12 +88,13 @@
 // Google is the default search engine set. If Google is not the default search
 // engine use the country provided by VariationsService. Fallback to a default
 // if we can't make an educated guess.
-std::string GetCountryToUse(Profile* profile,
+std::string GetCountryToUse(const TemplateURLService* template_url_service,
                             const std::string& override_country) {
   if (!override_country.empty())
     return override_country;
 
-  std::string country_code = GetDefaultSearchEngineCountryCode(profile);
+  std::string country_code = GetDefaultSearchEngineCountryCode(
+      template_url_service);
 
   if (country_code.empty())
     country_code = GetVariationsServiceCountry();
@@ -179,32 +175,44 @@
 
 PopularSites::Site::~Site() {}
 
-PopularSites::PopularSites(Profile* profile,
+PopularSites::PopularSites(PrefService* prefs,
+                           const TemplateURLService* template_url_service,
+                           net::URLRequestContextGetter* download_context,
                            const std::string& override_country,
                            const std::string& override_version,
                            bool force_download,
                            const FinishedCallback& callback)
-    : PopularSites(profile,
-                   GetCountryToUse(profile, override_country),
+    : PopularSites(prefs,
+                   template_url_service,
+                   download_context,
+                   GetCountryToUse(template_url_service, override_country),
                    GetVersionToUse(override_version),
                    GURL(),
                    force_download,
                    callback) {}
 
-PopularSites::PopularSites(Profile* profile,
+PopularSites::PopularSites(PrefService* prefs,
+                           const TemplateURLService* template_url_service,
+                           net::URLRequestContextGetter* download_context,
                            const GURL& url,
                            const FinishedCallback& callback)
-    : PopularSites(profile, std::string(), std::string(), url, true, callback) {
-}
+    : PopularSites(prefs,
+                   template_url_service,
+                   download_context,
+                   std::string(),
+                   std::string(),
+                   url,
+                   true,
+                   callback) {}
 
 PopularSites::~PopularSites() {}
 
 std::string PopularSites::GetCountry() const {
-  return profile_->GetPrefs()->GetString(kPopularSitesCountryPref);
+  return prefs_->GetString(kPopularSitesCountryPref);
 }
 
 std::string PopularSites::GetVersion() const {
-  return profile_->GetPrefs()->GetString(kPopularSitesVersionPref);
+  return prefs_->GetString(kPopularSitesVersionPref);
 }
 
 // static
@@ -215,7 +223,9 @@
   user_prefs->RegisterStringPref(kPopularSitesVersionPref, std::string());
 }
 
-PopularSites::PopularSites(Profile* profile,
+PopularSites::PopularSites(PrefService* prefs,
+                           const TemplateURLService* template_url_service,
+                           net::URLRequestContextGetter* download_context,
                            const std::string& country,
                            const std::string& version,
                            const GURL& override_url,
@@ -225,10 +235,12 @@
       pending_country_(country),
       pending_version_(version),
       local_path_(GetPopularSitesPath()),
-      profile_(profile),
+      prefs_(prefs),
+      template_url_service_(template_url_service),
+      download_context_(download_context),
       weak_ptr_factory_(this) {
   const base::Time last_download_time = base::Time::FromInternalValue(
-      profile_->GetPrefs()->GetInt64(kPopularSitesLastDownloadPref));
+      prefs_->GetInt64(kPopularSitesLastDownloadPref));
   const base::TimeDelta time_since_last_download =
       base::Time::Now() - last_download_time;
   const base::TimeDelta redownload_interval =
@@ -256,7 +268,7 @@
                                      bool force_download,
                                      bool is_fallback) {
   downloader_.reset(new FileDownloader(
-      url, local_path_, force_download, profile_->GetRequestContext(),
+      url, local_path_, force_download, download_context_,
       base::Bind(&PopularSites::OnDownloadDone, base::Unretained(this),
                  is_fallback)));
 }
@@ -264,13 +276,12 @@
 void PopularSites::OnDownloadDone(bool is_fallback,
                                   FileDownloader::Result result) {
   downloader_.reset();
-  PrefService* prefs = profile_->GetPrefs();
   switch (result) {
     case FileDownloader::DOWNLOADED:
-      prefs->SetInt64(kPopularSitesLastDownloadPref,
+      prefs_->SetInt64(kPopularSitesLastDownloadPref,
                       base::Time::Now().ToInternalValue());
-      prefs->SetString(kPopularSitesCountryPref, pending_country_);
-      prefs->SetString(kPopularSitesVersionPref, pending_version_);
+      prefs_->SetString(kPopularSitesCountryPref, pending_country_);
+      prefs_->SetString(kPopularSitesVersionPref, pending_version_);
       ParseSiteList(local_path_);
       break;
     case FileDownloader::EXISTS:
diff --git a/chrome/browser/android/ntp/popular_sites.h b/chrome/browser/android/ntp/popular_sites.h
index 7cc520e..41523c5b 100644
--- a/chrome/browser/android/ntp/popular_sites.h
+++ b/chrome/browser/android/ntp/popular_sites.h
@@ -25,7 +25,8 @@
 class PrefRegistrySyncable;
 }
 
-class Profile;
+class PrefService;
+class TemplateURLService;
 
 // Downloads and provides a list of suggested popular sites, for display on
 // the NTP when there are not enough personalized suggestions. Caches the
@@ -56,7 +57,9 @@
   // override the baked-in default version.
   // Set |force_download| to enforce re-downloading the suggestions file, even
   // if it already exists on disk.
-  PopularSites(Profile* profile,
+  PopularSites(PrefService* prefs,
+               const TemplateURLService* template_url_service,
+               net::URLRequestContextGetter* download_context,
                const std::string& override_country,
                const std::string& override_version,
                bool force_download,
@@ -64,7 +67,9 @@
 
   // This fetches the popular sites from a given url and is only used for
   // debugging through the popular-sites-internals page.
-  PopularSites(Profile* profile,
+  PopularSites(PrefService* prefs,
+               const TemplateURLService* template_url_service,
+               net::URLRequestContextGetter* download_context,
                const GURL& url,
                const FinishedCallback& callback);
 
@@ -83,7 +88,9 @@
       user_prefs::PrefRegistrySyncable* user_prefs);
 
  private:
-  PopularSites(Profile* profile,
+  PopularSites(PrefService* prefs,
+               const TemplateURLService* template_url_service,
+               net::URLRequestContextGetter* download_context,
                const std::string& country,
                const std::string& version,
                const GURL& override_url,
@@ -113,7 +120,9 @@
 
   base::FilePath local_path_;
 
-  Profile* profile_;
+  PrefService* prefs_;
+  const TemplateURLService* template_url_service_;
+  net::URLRequestContextGetter* download_context_;
 
   base::WeakPtrFactory<PopularSites> weak_ptr_factory_;
 
diff --git a/chrome/browser/android/offline_pages/offline_page_bridge.cc b/chrome/browser/android/offline_pages/offline_page_bridge.cc
index ea267e9..ded2d9c8 100644
--- a/chrome/browser/android/offline_pages/offline_page_bridge.cc
+++ b/chrome/browser/android/offline_pages/offline_page_bridge.cc
@@ -51,6 +51,23 @@
   }
 }
 
+void CheckPagesExistOfflineCallback(
+    const ScopedJavaGlobalRef<jobject>& j_callback_obj,
+    const OfflinePageModel::CheckPagesExistOfflineResult& offline_pages) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+
+  std::vector<std::string> offline_pages_vector;
+  for (const GURL& page : offline_pages)
+    offline_pages_vector.push_back(page.spec());
+
+  ScopedJavaLocalRef<jobjectArray> j_result_array =
+      base::android::ToJavaArrayOfStrings(env, offline_pages_vector);
+  DCHECK(j_result_array.obj());
+
+  Java_CheckPagesExistOfflineCallbackInternal_onResult(
+      env, j_callback_obj.obj(), j_result_array.obj());
+}
+
 void GetAllPagesCallback(const ScopedJavaGlobalRef<jobject>& j_result_obj,
                          const ScopedJavaGlobalRef<jobject>& j_callback_obj,
                          const OfflinePageModel::GetAllPagesResult& result) {
@@ -179,6 +196,27 @@
       name_space, base::Bind(&HasPagesCallback, j_callback_ref));
 }
 
+void OfflinePageBridge::CheckPagesExistOffline(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj,
+    const JavaParamRef<jobjectArray>& j_urls_array,
+    const JavaParamRef<jobject>& j_callback_obj) {
+  DCHECK(j_urls_array);
+  DCHECK(j_callback_obj);
+
+  std::vector<std::string> urls;
+  base::android::AppendJavaStringArrayToStringVector(env, j_urls_array.obj(),
+                                                     &urls);
+
+  std::set<GURL> page_urls;
+  for (const std::string& url : urls)
+    page_urls.insert(GURL(url));
+
+  offline_page_model_->CheckPagesExistOffline(
+      page_urls, base::Bind(&CheckPagesExistOfflineCallback,
+                            ScopedJavaGlobalRef<jobject>(env, j_callback_obj)));
+}
+
 void OfflinePageBridge::GetAllPages(
     JNIEnv* env,
     const JavaParamRef<jobject>& obj,
diff --git a/chrome/browser/android/offline_pages/offline_page_bridge.h b/chrome/browser/android/offline_pages/offline_page_bridge.h
index d8a3040..73fe91d 100644
--- a/chrome/browser/android/offline_pages/offline_page_bridge.h
+++ b/chrome/browser/android/offline_pages/offline_page_bridge.h
@@ -44,6 +44,12 @@
                 const base::android::JavaParamRef<jstring>& name_space,
                 const base::android::JavaParamRef<jobject>& j_callback_obj);
 
+  void CheckPagesExistOffline(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj,
+      const base::android::JavaParamRef<jobjectArray>& j_urls_array,
+      const base::android::JavaParamRef<jobject>& j_callback_obj);
+
   void GetAllPages(JNIEnv* env,
                    const base::android::JavaParamRef<jobject>& obj,
                    const base::android::JavaParamRef<jobject>& j_result_obj,
diff --git a/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc b/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc
index 9647723..c8a839c 100644
--- a/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc
+++ b/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc
@@ -995,9 +995,9 @@
   // make sure we keep rendering popups correct in webview.
 }
 
-// Flaky on ChromeOS: http://crbug.com/526886
-// Causes problems on windows: http://crbug.com/544037
-#if defined(OS_CHROMEOS) || defined(OS_WIN)
+// Flaky on ChromeOS and Linux: http://crbug.com/526886
+// Causes problems on windows: http://crbug.com/544998
+#if defined(OS_CHROMEOS) || defined(OS_WIN) || defined(OS_LINUX)
 #define MAYBE_PopupPositioningMoved DISABLED_PopupPositioningMoved
 #else
 #define MAYBE_PopupPositioningMoved PopupPositioningMoved
diff --git a/chrome/browser/chromeos/arc/arc_policy_bridge.cc b/chrome/browser/chromeos/arc/arc_policy_bridge.cc
index 5ad15000..58d92fc 100644
--- a/chrome/browser/chromeos/arc/arc_policy_bridge.cc
+++ b/chrome/browser/chromeos/arc/arc_policy_bridge.cc
@@ -115,6 +115,9 @@
                policy_map, 2 /*BlockGeolocation*/, &filtered_policies);
   MapBoolToBool("unmuteMicrophoneDisabled", policy::key::kAudioCaptureAllowed,
                 policy_map, true, &filtered_policies);
+  MapBoolToBool("usbFileTransferDisabled",
+                policy::key::kExternalStorageDisabled, policy_map, false,
+                &filtered_policies);
 
   // Add global app restrictions.
   AddGlobalAppRestriction("com.android.browser:URLBlacklist",
diff --git a/chrome/browser/chromeos/arc/arc_policy_bridge_unittest.cc b/chrome/browser/chromeos/arc/arc_policy_bridge_unittest.cc
index 4b3f7f1..da58e3a 100644
--- a/chrome/browser/chromeos/arc/arc_policy_bridge_unittest.cc
+++ b/chrome/browser/chromeos/arc/arc_policy_bridge_unittest.cc
@@ -164,6 +164,15 @@
       PolicyStringCallback("{\"shareLocationDisabled\":false}"));
 }
 
+TEST_F(ArcPolicyBridgeTest, ExternalStorageDisabledTest) {
+  policy_map().Set(policy::key::kExternalStorageDisabled,
+                   policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
+                   policy::POLICY_SOURCE_CLOUD,
+                   new base::FundamentalValue(true), nullptr);
+  policy_bridge()->GetPolicies(
+      PolicyStringCallback("{\"usbFileTransferDisabled\":true}"));
+}
+
 TEST_F(ArcPolicyBridgeTest, URLBlacklistTest) {
   base::ListValue blacklist;
   blacklist.Append(new base::StringValue("www.blacklist1.com"));
diff --git a/chrome/browser/extensions/extension_install_prompt.h b/chrome/browser/extensions/extension_install_prompt.h
index f71eb801..13ee5bf 100644
--- a/chrome/browser/extensions/extension_install_prompt.h
+++ b/chrome/browser/extensions/extension_install_prompt.h
@@ -260,13 +260,6 @@
   // The implementations of this function are platform-specific.
   static ShowDialogCallback GetDefaultShowDialogCallback();
 
-  // Callback to show the Views extension install dialog. Don't use this; it is
-  // a temporary hack for MacViews.
-  // TODO(ellyjones): Remove this.
-#if defined(OS_MACOSX)
-  static ShowDialogCallback GetViewsShowDialogCallback();
-#endif
-
   // Returns the appropriate prompt type for the given |extension|.
   // TODO(devlin): This method is yucky - callers probably only care about one
   // prompt type. We just need to comb through and figure out what it is.
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc
index 0c11394..97ceb0b 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -222,6 +222,10 @@
     return false;
   }
 
+  // Prevent the autofill password manager from prompting the second time.
+  if (type == password_manager::CredentialSourceType::CREDENTIAL_SOURCE_API)
+    password_manager_.DropFormManagers();
+
   if (IsTheHotNewBubbleUIEnabled()) {
 #if !BUILDFLAG(ANDROID_JAVA_UI)
     PasswordsClientUIDelegate* manage_passwords_ui_controller =
diff --git a/chrome/browser/password_manager/credential_manager_browsertest.cc b/chrome/browser/password_manager/credential_manager_browsertest.cc
index c8889467..378d660 100644
--- a/chrome/browser/password_manager/credential_manager_browsertest.cc
+++ b/chrome/browser/password_manager/credential_manager_browsertest.cc
@@ -122,4 +122,29 @@
   EXPECT_FALSE(prompt_observer->IsShowingPrompt());
 }
 
+IN_PROC_BROWSER_TEST_F(CredentialManagerBrowserTest, SaveViaAPIAndAutofill) {
+  NavigateToFile("/password/password_form.html");
+  std::string fill_password =
+  "document.getElementById('username_field').value = 'user';"
+  "document.getElementById('password_field').value = '12345';";
+  ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_password));
+
+  // Call the API to save the form.
+  ASSERT_TRUE(content::ExecuteScript(
+      RenderViewHost(),
+      "var c = new PasswordCredential({ id: 'user', password: '12345' });"
+      "navigator.credentials.store(c);"));
+  std::unique_ptr<PromptObserver> prompt_observer(
+      PromptObserver::Create(WebContents()));
+  EXPECT_TRUE(prompt_observer->IsShowingPrompt());
+  prompt_observer->Dismiss();
+
+  NavigationObserver form_submit_observer(WebContents());
+  ASSERT_TRUE(content::ExecuteScript(
+      RenderViewHost(),
+      "document.getElementById('input_submit_button').click();"));
+  form_submit_observer.Wait();
+  EXPECT_FALSE(prompt_observer->IsShowingPrompt());
+}
+
 }  // namespace
diff --git a/chrome/browser/password_manager/password_manager_test_base.cc b/chrome/browser/password_manager/password_manager_test_base.cc
index bdd32c3..909c9f9 100644
--- a/chrome/browser/password_manager/password_manager_test_base.cc
+++ b/chrome/browser/password_manager/password_manager_test_base.cc
@@ -14,7 +14,7 @@
 #include "chrome/browser/password_manager/password_store_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/passwords/passwords_model_delegate.h"
+#include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
@@ -24,6 +24,7 @@
 #include "components/password_manager/core/browser/password_manager_test_utils.h"
 #include "components/password_manager/core/browser/test_password_store.h"
 #include "components/password_manager/core/common/password_manager_features.h"
+#include "content/public/browser/navigation_details.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_utils.h"
@@ -95,6 +96,10 @@
       infobar_service_->RemoveObserver(this);
   }
 
+  void Dismiss() const override {
+    NOTIMPLEMENTED();
+  }
+
  private:
   // PromptObserver:
   bool IsShowingPrompt() const override { return infobar_is_being_shown_; }
@@ -143,6 +148,17 @@
 
   ~BubbleObserver() override {}
 
+  void Dismiss() const override {
+    passwords_model_delegate_->OnBubbleHidden();
+    // Navigate away to reset the state to inactive.
+    static_cast<content::WebContentsObserver*>(
+        static_cast<ManagePasswordsUIController*>(passwords_model_delegate_))
+            ->DidNavigateMainFrame(content::LoadCommittedDetails(),
+                                   content::FrameNavigateParams());
+    ASSERT_EQ(password_manager::ui::INACTIVE_STATE,
+              passwords_model_delegate_->GetState());
+  }
+
  private:
   // PromptObserver:
   bool IsShowingPrompt() const override {
diff --git a/chrome/browser/password_manager/password_manager_test_base.h b/chrome/browser/password_manager/password_manager_test_base.h
index 0ca5179..a0f411f8 100644
--- a/chrome/browser/password_manager/password_manager_test_base.h
+++ b/chrome/browser/password_manager/password_manager_test_base.h
@@ -67,6 +67,10 @@
   // Checks if the update prompt is being currently shown.
   virtual bool IsShowingUpdatePrompt() const;
 
+  // Dismisses the prompt currently open and moves the controller to the
+  // inactive state.
+  virtual void Dismiss() const = 0;
+
   // Expecting that the prompt is shown, saves the password. Checks that the
   // prompt is no longer visible afterwards.
   void Accept() const;
diff --git a/chrome/browser/prerender/prerender_histograms.cc b/chrome/browser/prerender/prerender_histograms.cc
index 6e46198..30d9f03 100644
--- a/chrome/browser/prerender/prerender_histograms.cc
+++ b/chrome/browser/prerender/prerender_histograms.cc
@@ -47,7 +47,7 @@
     case ORIGIN_LINK_REL_PRERENDER_CROSSDOMAIN:
       return ComposeHistogramName("webcross", name);
     case ORIGIN_EXTERNAL_REQUEST:
-        return ComposeHistogramName("externalrequest", name);
+      return ComposeHistogramName("externalrequest", name);
     case ORIGIN_INSTANT:
       return ComposeHistogramName("Instant", name);
     case ORIGIN_LINK_REL_NEXT:
@@ -56,6 +56,8 @@
       return ComposeHistogramName("gws", name);
     case ORIGIN_EXTERNAL_REQUEST_FORCED_CELLULAR:
       return ComposeHistogramName("externalrequestforced", name);
+    case ORIGIN_OFFLINE:
+      return ComposeHistogramName("offline", name);
     default:
       NOTREACHED();
       break;
@@ -91,6 +93,7 @@
   } \
   /* Do not rename.  HISTOGRAM expects a local variable "name". */ \
   std::string name = GetHistogramName(origin, wash, histogram_name); \
+  /* Branching because HISTOGRAM is caching the histogram into a static. */ \
   if (wash) { \
     HISTOGRAM; \
   } else if (origin == ORIGIN_OMNIBOX) { \
@@ -109,6 +112,8 @@
     HISTOGRAM; \
   } else if (origin == ORIGIN_EXTERNAL_REQUEST_FORCED_CELLULAR) { \
     HISTOGRAM; \
+  } else if (origin == ORIGIN_OFFLINE) { \
+    HISTOGRAM; \
   } else { \
     HISTOGRAM; \
   } \
diff --git a/chrome/browser/prerender/prerender_manager.cc b/chrome/browser/prerender/prerender_manager.cc
index 17bb6d91..f3dedfe 100644
--- a/chrome/browser/prerender/prerender_manager.cc
+++ b/chrome/browser/prerender/prerender_manager.cc
@@ -320,6 +320,14 @@
                       session_storage_namespace);
 }
 
+PrerenderHandle* PrerenderManager::AddPrerenderForOffline(
+    const GURL& url,
+    content::SessionStorageNamespace* session_storage_namespace,
+    const gfx::Size& size) {
+  return AddPrerender(ORIGIN_OFFLINE, url, content::Referrer(), size,
+                      session_storage_namespace);
+}
+
 void PrerenderManager::CancelAllPrerenders() {
   DCHECK(CalledOnValidThread());
   while (!active_prerenders_.empty()) {
@@ -951,7 +959,8 @@
   // histogram tracking.
   histograms_->RecordPrerender(origin, url_arg);
 
-  if (profile_->GetPrefs()->GetBoolean(prefs::kBlockThirdPartyCookies)) {
+  if (profile_->GetPrefs()->GetBoolean(prefs::kBlockThirdPartyCookies) &&
+      origin != ORIGIN_OFFLINE) {
     RecordFinalStatusWithoutCreatingPrerenderContents(
         url, origin, FINAL_STATUS_BLOCK_THIRD_PARTY_COOKIES);
     return nullptr;
@@ -1147,8 +1156,12 @@
     const SessionStorageNamespace* session_storage_namespace) {
   for (ScopedVector<PrerenderData>::iterator it = active_prerenders_.begin();
        it != active_prerenders_.end(); ++it) {
-    if ((*it)->contents()->Matches(url, session_storage_namespace))
+    PrerenderContents* contents = (*it)->contents();
+    if (contents->Matches(url, session_storage_namespace)) {
+      if (contents->origin() == ORIGIN_OFFLINE)
+        return NULL;
       return *it;
+    }
   }
   return NULL;
 }
@@ -1169,6 +1182,11 @@
   base::TimeDelta elapsed_time =
       GetCurrentTimeTicks() - last_prerender_start_time_;
   histograms_->RecordTimeBetweenPrerenderRequests(origin, elapsed_time);
+  // TODO(gabadie,pasko): Re-implement missing tests for
+  // FINAL_STATUS_RATE_LIMIT_EXCEEDED that where removed by:
+  //    http://crrev.com/a2439eeab37f7cb7a118493fb55ec0cb07f93b49.
+  if (origin == ORIGIN_OFFLINE)
+    return true;
   if (!config_.rate_limit_enabled)
     return true;
   return elapsed_time >=
@@ -1311,10 +1329,18 @@
     Origin origin) const {
   DCHECK(CalledOnValidThread());
 
-  // LINK rel=prerender origins ignore the network state and the privacy
-  // settings.
+  // <link rel=prerender> origins ignore the network state and the privacy
+  // settings. Web developers should be able prefetch with all possible privacy
+  // settings and with all possible network types. This would avoid web devs
+  // coming up with creative ways to prefetch in cases they are not allowed to
+  // do so.
+  //
+  // Offline originated prerenders also ignore the network state and privacy
+  // settings because they are controlled by the offliner logic via
+  // PrerenderHandle.
   if (origin == ORIGIN_LINK_REL_PRERENDER_SAMEDOMAIN ||
-      origin == ORIGIN_LINK_REL_PRERENDER_CROSSDOMAIN) {
+      origin == ORIGIN_LINK_REL_PRERENDER_CROSSDOMAIN ||
+      origin == ORIGIN_OFFLINE) {
     return NetworkPredictionStatus::ENABLED;
   }
 
diff --git a/chrome/browser/prerender/prerender_manager.h b/chrome/browser/prerender/prerender_manager.h
index 692d971..d64fc202f 100644
--- a/chrome/browser/prerender/prerender_manager.h
+++ b/chrome/browser/prerender/prerender_manager.h
@@ -151,6 +151,22 @@
       content::SessionStorageNamespace* session_storage_namespace,
       const gfx::Size& size);
 
+  // Adds a prerender for the background loader. Returns a caller-owned
+  // PrerenderHandle* if the URL was added, NULL if it was not.
+  //
+  // The caller may set an observer on the handle to receive load events. When
+  // the caller is done using the WebContents, it should call OnCancel() on the
+  // handle to free the resources associated with the prerender.
+  //
+  // The caller must provide two guarantees:
+  // 1. It must never ask for a swap-in;
+  // 2. The SessionStorageNamespace must not be shared with any tab / page load
+  //    to avoid swapping in from there.
+  PrerenderHandle* AddPrerenderForOffline(
+      const GURL& url,
+      content::SessionStorageNamespace* session_storage_namespace,
+      const gfx::Size& size);
+
   // Cancels all active prerenders.
   void CancelAllPrerenders();
 
diff --git a/chrome/browser/prerender/prerender_origin.cc b/chrome/browser/prerender/prerender_origin.cc
index 3c9b7b69..b674d62 100644
--- a/chrome/browser/prerender/prerender_origin.cc
+++ b/chrome/browser/prerender/prerender_origin.cc
@@ -27,6 +27,7 @@
   "Instant",
   "Link Rel Next",
   "External Request Forced Cellular",
+  "Offline",
   "Max",
 };
 static_assert(arraysize(kOriginNames) == ORIGIN_MAX + 1,
diff --git a/chrome/browser/prerender/prerender_origin.h b/chrome/browser/prerender/prerender_origin.h
index 60e3e0b..cb82294 100644
--- a/chrome/browser/prerender/prerender_origin.h
+++ b/chrome/browser/prerender/prerender_origin.h
@@ -24,6 +24,7 @@
   ORIGIN_INSTANT = 11,
   ORIGIN_LINK_REL_NEXT = 12,
   ORIGIN_EXTERNAL_REQUEST_FORCED_CELLULAR = 13,
+  ORIGIN_OFFLINE = 14,
   ORIGIN_MAX,
 };
 
diff --git a/chrome/browser/prerender/prerender_unittest.cc b/chrome/browser/prerender/prerender_unittest.cc
index 0db797f2..ee3254a1 100644
--- a/chrome/browser/prerender/prerender_unittest.cc
+++ b/chrome/browser/prerender/prerender_unittest.cc
@@ -427,6 +427,24 @@
   EXPECT_FALSE(AddSimplePrerender(url));
 }
 
+TEST_F(PrerenderTest, OfflinePrerenderIgnoresThirdPartyCookiesPref) {
+  GURL url("http://www.google.com/");
+  RestorePrerenderMode restore_prerender_mode;
+  ASSERT_TRUE(PrerenderManager::IsPrerenderingPossible());
+
+  profile()->GetPrefs()->SetBoolean(prefs::kBlockThirdPartyCookies, true);
+  DummyPrerenderContents* prerender_contents =
+      prerender_manager()->CreateNextPrerenderContents(
+          url, ORIGIN_OFFLINE, FINAL_STATUS_MANAGER_SHUTDOWN);
+  std::unique_ptr<PrerenderHandle> prerender_handle(
+      prerender_manager()->AddPrerenderForOffline(url, nullptr, kSize));
+  EXPECT_TRUE(prerender_handle);
+  EXPECT_TRUE(prerender_handle->IsPrerendering());
+  EXPECT_TRUE(prerender_contents->prerendering_has_started());
+  EXPECT_EQ(prerender_contents, prerender_handle->contents());
+  EXPECT_EQ(ORIGIN_OFFLINE, prerender_handle->contents()->origin());
+}
+
 TEST_F(PrerenderTest, FoundTest) {
   GURL url("http://www.google.com/");
   DummyPrerenderContents* prerender_contents =
@@ -438,6 +456,19 @@
   ASSERT_EQ(prerender_contents, prerender_manager()->FindAndUseEntry(url));
 }
 
+TEST_F(PrerenderTest, UnfindableOfflinePrerenderTest) {
+  GURL url("http://www.google.com/");
+  DummyPrerenderContents* prerender_contents =
+      prerender_manager()->CreateNextPrerenderContents(
+          url, ORIGIN_OFFLINE, FINAL_STATUS_MANAGER_SHUTDOWN);
+  std::unique_ptr<PrerenderHandle> prerender_handle(
+      prerender_manager()->AddPrerenderForOffline(url, nullptr, kSize));
+  EXPECT_TRUE(prerender_handle);
+  EXPECT_TRUE(prerender_handle->IsPrerendering());
+  EXPECT_TRUE(prerender_contents->prerendering_has_started());
+  ASSERT_EQ(nullptr, prerender_manager()->FindAndUseEntry(url));
+}
+
 // Make sure that if queue a request, and a second prerender request for the
 // same URL comes in, that the second request attaches to the first prerender,
 // and we don't use the second prerender contents.
@@ -1111,28 +1142,41 @@
   EXPECT_FALSE(prerender_contents->prerendering_has_started());
 }
 
-TEST_F(PrerenderTest,PrerenderAllowedOnCellularWithForcedOrigin) {
+TEST_F(PrerenderTest, PrerenderAllowedForOfflineAndForcedCellular) {
+  const Origin origins[] = {
+    ORIGIN_EXTERNAL_REQUEST_FORCED_CELLULAR,
+    ORIGIN_OFFLINE,
+  };
+
   EnablePrerender();
   std::unique_ptr<net::NetworkChangeNotifier> mock(
       new MockNetworkChangeNotifier4G);
   EXPECT_TRUE(net::NetworkChangeNotifier::IsConnectionCellular(
       net::NetworkChangeNotifier::GetConnectionType()));
   GURL url("http://www.google.com/");
-  DummyPrerenderContents* prerender_contents =
-      prerender_manager()->CreateNextPrerenderContents(
-          url,
-          ORIGIN_EXTERNAL_REQUEST_FORCED_CELLULAR,
-          FINAL_STATUS_USED);
-  std::unique_ptr<PrerenderHandle> prerender_handle(
-      prerender_manager()->AddPrerenderOnCellularFromExternalRequest(
-          url, content::Referrer(), nullptr, kSize));
-  EXPECT_TRUE(prerender_handle);
-  EXPECT_TRUE(prerender_handle->IsPrerendering());
-  EXPECT_TRUE(prerender_contents->prerendering_has_started());
-  EXPECT_EQ(prerender_contents, prerender_handle->contents());
-  EXPECT_EQ(ORIGIN_EXTERNAL_REQUEST_FORCED_CELLULAR,
-    prerender_handle->contents()->origin());
-  ASSERT_EQ(prerender_contents, prerender_manager()->FindAndUseEntry(url));
+  for (Origin origin: origins) {
+    DummyPrerenderContents* prerender_contents = nullptr;
+    std::unique_ptr<PrerenderHandle> prerender_handle;
+    if (origin == ORIGIN_OFFLINE) {
+      prerender_contents = prerender_manager()->CreateNextPrerenderContents(
+          url, origin, FINAL_STATUS_MANAGER_SHUTDOWN);
+      prerender_handle.reset(prerender_manager()->AddPrerenderForOffline(
+          url, nullptr, kSize));
+    } else {
+      prerender_contents = prerender_manager()->CreateNextPrerenderContents(
+          url, origin, FINAL_STATUS_USED);
+      prerender_handle.reset(
+          prerender_manager()->AddPrerenderOnCellularFromExternalRequest(
+              url, content::Referrer(), nullptr, kSize));
+    }
+    EXPECT_TRUE(prerender_handle);
+    EXPECT_TRUE(prerender_handle->IsPrerendering());
+    EXPECT_TRUE(prerender_contents->prerendering_has_started());
+    EXPECT_EQ(prerender_contents, prerender_handle->contents());
+    EXPECT_EQ(origin, prerender_handle->contents()->origin());
+    if (origin != ORIGIN_OFFLINE)
+      ASSERT_EQ(prerender_contents, prerender_manager()->FindAndUseEntry(url));
+  }
 }
 
 TEST_F(PrerenderTest, LinkManagerCancel) {
diff --git a/chrome/browser/profiles/off_the_record_profile_io_data.cc b/chrome/browser/profiles/off_the_record_profile_io_data.cc
index 8ac61f1..13e8f7f 100644
--- a/chrome/browser/profiles/off_the_record_profile_io_data.cc
+++ b/chrome/browser/profiles/off_the_record_profile_io_data.cc
@@ -332,11 +332,23 @@
   // extensions API, but we need to update it to understand isolated apps first.
   context->SetCookieStore(
       content::CreateCookieStore(content::CookieStoreConfig()));
+  std::unique_ptr<net::ChannelIDService> channel_id_service(
+      new net::ChannelIDService(new net::DefaultChannelIDStore(nullptr),
+                                base::WorkerPool::GetTaskRunner(true)));
+
+  // Build a new HttpNetworkSession that uses the new ChannelIDService.
+  net::HttpNetworkSession::Params network_params =
+      http_network_session_->params();
+  network_params.channel_id_service = channel_id_service.get();
+  std::unique_ptr<net::HttpNetworkSession> http_network_session(
+      new net::HttpNetworkSession(network_params));
 
   // Use a separate in-memory cache for the app.
   std::unique_ptr<net::HttpCache> app_http_cache = CreateHttpFactory(
-      http_network_session_.get(), net::HttpCache::DefaultBackend::InMemory(0));
+      http_network_session.get(), net::HttpCache::DefaultBackend::InMemory(0));
 
+  context->SetChannelIDService(std::move(channel_id_service));
+  context->SetHttpNetworkSession(std::move(http_network_session));
   context->SetHttpTransactionFactory(std::move(app_http_cache));
 
   std::unique_ptr<net::URLRequestJobFactoryImpl> job_factory(
diff --git a/chrome/browser/profiles/profile_browsertest.cc b/chrome/browser/profiles/profile_browsertest.cc
index 2dc8064..cc98501 100644
--- a/chrome/browser/profiles/profile_browsertest.cc
+++ b/chrome/browser/profiles/profile_browsertest.cc
@@ -38,6 +38,10 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/test/test_utils.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/extension_builder.h"
+#include "extensions/common/value_builder.h"
 #include "net/base/net_errors.h"
 #include "net/test/url_request/url_request_failed_job.h"
 #include "net/url_request/url_fetcher.h"
@@ -421,6 +425,133 @@
   FlushIoTaskRunnerAndSpinThreads();
 }
 
+namespace {
+
+scoped_refptr<const extensions::Extension> BuildTestApp(Profile* profile) {
+  scoped_refptr<const extensions::Extension> app;
+  app =
+      extensions::ExtensionBuilder()
+          .SetManifest(
+              extensions::DictionaryBuilder()
+                  .Set("name", "test app")
+                  .Set("version", "1")
+                  .Set("app",
+                       extensions::DictionaryBuilder()
+                           .Set("background",
+                                extensions::DictionaryBuilder()
+                                    .Set("scripts", extensions::ListBuilder()
+                                                        .Append("background.js")
+                                                        .Build())
+                                    .Build())
+                           .Build())
+                  .Build())
+          .Build();
+  extensions::ExtensionRegistry* registry =
+      extensions::ExtensionRegistry::Get(profile);
+  EXPECT_TRUE(registry->AddEnabled(app));
+  return app;
+}
+
+void CompareURLRequestContexts(
+    net::URLRequestContextGetter* extension_context_getter,
+    net::URLRequestContextGetter* main_context_getter) {
+  net::URLRequestContext* extension_context =
+      extension_context_getter->GetURLRequestContext();
+  net::URLRequestContext* main_context =
+      main_context_getter->GetURLRequestContext();
+
+  // Check that the URLRequestContexts are different and that their
+  // ChannelIDServices and CookieStores are different.
+  EXPECT_NE(extension_context, main_context);
+  EXPECT_NE(extension_context->channel_id_service(),
+            main_context->channel_id_service());
+  EXPECT_NE(extension_context->cookie_store(), main_context->cookie_store());
+
+  // Check that the ChannelIDService in the HttpNetworkSession is the same as
+  // the one directly on the URLRequestContext.
+  EXPECT_EQ(extension_context->http_transaction_factory()
+                ->GetSession()
+                ->params()
+                .channel_id_service,
+            extension_context->channel_id_service());
+  EXPECT_EQ(main_context->http_transaction_factory()
+                ->GetSession()
+                ->params()
+                .channel_id_service,
+            main_context->channel_id_service());
+}
+
+}  // namespace
+
+IN_PROC_BROWSER_TEST_F(ProfileBrowserTest, URLRequestContextIsolation) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+
+  MockProfileDelegate delegate;
+  EXPECT_CALL(delegate, OnProfileCreated(testing::NotNull(), true, true));
+
+  {
+    std::unique_ptr<Profile> profile(CreateProfile(
+        temp_dir.path(), &delegate, Profile::CREATE_MODE_SYNCHRONOUS));
+
+    scoped_refptr<const extensions::Extension> app =
+        BuildTestApp(profile.get());
+    content::StoragePartition* extension_partition =
+        content::BrowserContext::GetStoragePartitionForSite(
+            profile.get(),
+            extensions::Extension::GetBaseURLFromExtensionId(app->id()));
+    net::URLRequestContextGetter* extension_context_getter =
+        extension_partition->GetURLRequestContext();
+    net::URLRequestContextGetter* main_context_getter =
+        profile->GetRequestContext();
+
+    base::RunLoop run_loop;
+    content::BrowserThread::PostTaskAndReply(
+        content::BrowserThread::IO, FROM_HERE,
+        base::Bind(&CompareURLRequestContexts, extension_context_getter,
+                   main_context_getter),
+        run_loop.QuitClosure());
+    run_loop.Run();
+  }
+
+  FlushIoTaskRunnerAndSpinThreads();
+}
+
+IN_PROC_BROWSER_TEST_F(ProfileBrowserTest,
+                       OffTheRecordURLRequestContextIsolation) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+
+  MockProfileDelegate delegate;
+  EXPECT_CALL(delegate, OnProfileCreated(testing::NotNull(), true, true));
+
+  {
+    std::unique_ptr<Profile> profile(CreateProfile(
+        temp_dir.path(), &delegate, Profile::CREATE_MODE_SYNCHRONOUS));
+    Profile* otr_profile = profile->GetOffTheRecordProfile();
+
+    scoped_refptr<const extensions::Extension> app = BuildTestApp(otr_profile);
+    content::StoragePartition* extension_partition =
+        content::BrowserContext::GetStoragePartitionForSite(
+            otr_profile,
+            extensions::Extension::GetBaseURLFromExtensionId(app->id()));
+    net::URLRequestContextGetter* extension_context_getter =
+        extension_partition->GetURLRequestContext();
+    net::URLRequestContextGetter* main_context_getter =
+        otr_profile->GetRequestContext();
+
+    base::RunLoop run_loop;
+    content::BrowserThread::PostTaskAndReply(
+        content::BrowserThread::IO, FROM_HERE,
+        base::Bind(&CompareURLRequestContexts, extension_context_getter,
+                   main_context_getter),
+        run_loop.QuitClosure());
+    run_loop.Run();
+  }
+
+  FlushIoTaskRunnerAndSpinThreads();
+}
+
 // The EndSession IO synchronization is only critical on Windows, but also
 // happens under the USE_X11 define. See BrowserProcessImpl::EndSession.
 #if defined(USE_X11) || defined(OS_WIN) || defined(USE_OZONE)
diff --git a/chrome/browser/profiles/profile_impl_io_data.cc b/chrome/browser/profiles/profile_impl_io_data.cc
index 59860504..93c99e4 100644
--- a/chrome/browser/profiles/profile_impl_io_data.cc
+++ b/chrome/browser/profiles/profile_impl_io_data.cc
@@ -623,6 +623,8 @@
 
   base::FilePath cookie_path = partition_descriptor.path.Append(
       chrome::kCookieFilename);
+  base::FilePath channel_id_path =
+      partition_descriptor.path.Append(chrome::kChannelIDFilename);
   base::FilePath cache_path =
       partition_descriptor.path.Append(chrome::kCacheDirname);
 
@@ -638,10 +640,9 @@
         app_cache_max_size_,
         BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE)));
   }
-  std::unique_ptr<net::HttpCache> app_http_cache =
-      CreateHttpFactory(http_network_session_.get(), std::move(app_backend));
 
   std::unique_ptr<net::CookieStore> cookie_store;
+  scoped_refptr<net::SQLiteChannelIDStore> channel_id_db;
   if (partition_descriptor.in_memory) {
     cookie_store = content::CreateCookieStore(content::CookieStoreConfig());
   } else {
@@ -656,7 +657,29 @@
         nullptr, nullptr);
     cookie_config.crypto_delegate = cookie_config::GetCookieCryptoDelegate();
     cookie_store = content::CreateCookieStore(cookie_config);
+    channel_id_db = new net::SQLiteChannelIDStore(
+        channel_id_path,
+        BrowserThread::GetBlockingPool()->GetSequencedTaskRunner(
+            base::SequencedWorkerPool::GetSequenceToken()));
   }
+  std::unique_ptr<net::ChannelIDService> channel_id_service(
+      new net::ChannelIDService(
+          new net::DefaultChannelIDStore(channel_id_db.get()),
+          base::WorkerPool::GetTaskRunner(true)));
+
+  // Build a new HttpNetworkSession that uses the new ChannelIDService.
+  net::HttpNetworkSession::Params network_params =
+      http_network_session_->params();
+  network_params.channel_id_service = channel_id_service.get();
+  std::unique_ptr<net::HttpNetworkSession> http_network_session(
+      new net::HttpNetworkSession(network_params));
+  std::unique_ptr<net::HttpCache> app_http_cache =
+      CreateHttpFactory(http_network_session.get(), std::move(app_backend));
+
+  // Transfer ownership of the ChannelIDStore and the HttpNetworkSession to the
+  // AppRequestContext.
+  context->SetChannelIDService(std::move(channel_id_service));
+  context->SetHttpNetworkSession(std::move(http_network_session));
 
   // Transfer ownership of the cookies and cache to AppRequestContext.
   context->SetCookieStore(std::move(cookie_store));
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc
index 39ec762..5a82008 100644
--- a/chrome/browser/profiles/profile_io_data.cc
+++ b/chrome/browser/profiles/profile_io_data.cc
@@ -573,6 +573,17 @@
   set_cookie_store(cookie_store_.get());
 }
 
+void ProfileIOData::AppRequestContext::SetChannelIDService(
+    std::unique_ptr<net::ChannelIDService> channel_id_service) {
+  channel_id_service_ = std::move(channel_id_service);
+  set_channel_id_service(channel_id_service_.get());
+}
+
+void ProfileIOData::AppRequestContext::SetHttpNetworkSession(
+    std::unique_ptr<net::HttpNetworkSession> http_network_session) {
+  http_network_session_ = std::move(http_network_session);
+}
+
 void ProfileIOData::AppRequestContext::SetHttpTransactionFactory(
     std::unique_ptr<net::HttpTransactionFactory> http_factory) {
   http_factory_ = std::move(http_factory);
diff --git a/chrome/browser/profiles/profile_io_data.h b/chrome/browser/profiles/profile_io_data.h
index de32c6e..46f218b5 100644
--- a/chrome/browser/profiles/profile_io_data.h
+++ b/chrome/browser/profiles/profile_io_data.h
@@ -267,6 +267,10 @@
     AppRequestContext();
 
     void SetCookieStore(std::unique_ptr<net::CookieStore> cookie_store);
+    void SetChannelIDService(
+        std::unique_ptr<net::ChannelIDService> channel_id_service);
+    void SetHttpNetworkSession(
+        std::unique_ptr<net::HttpNetworkSession> http_network_session);
     void SetHttpTransactionFactory(
         std::unique_ptr<net::HttpTransactionFactory> http_factory);
     void SetJobFactory(std::unique_ptr<net::URLRequestJobFactory> job_factory);
@@ -275,6 +279,8 @@
     ~AppRequestContext() override;
 
     std::unique_ptr<net::CookieStore> cookie_store_;
+    std::unique_ptr<net::ChannelIDService> channel_id_service_;
+    std::unique_ptr<net::HttpNetworkSession> http_network_session_;
     std::unique_ptr<net::HttpTransactionFactory> http_factory_;
     std::unique_ptr<net::URLRequestJobFactory> job_factory_;
   };
diff --git a/chrome/browser/safe_browsing/safe_browsing_service.cc b/chrome/browser/safe_browsing/safe_browsing_service.cc
index a9e5bfc1..4cc6b1a 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_service.cc
@@ -20,6 +20,7 @@
 #include "base/strings/string_util.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_restrictions.h"
+#include "base/threading/worker_pool.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
@@ -46,6 +47,11 @@
 #include "google_apis/google_api_keys.h"
 #include "net/cookies/cookie_store.h"
 #include "net/extras/sqlite/cookie_crypto_delegate.h"
+#include "net/extras/sqlite/sqlite_channel_id_store.h"
+#include "net/http/http_network_layer.h"
+#include "net/http/http_transaction_factory.h"
+#include "net/ssl/channel_id_service.h"
+#include "net/ssl/default_channel_id_store.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_getter.h"
 
@@ -80,6 +86,8 @@
 
 // Filename suffix for the cookie database.
 const base::FilePath::CharType kCookiesFile[] = FILE_PATH_LITERAL(" Cookies");
+const base::FilePath::CharType kChannelIDFile[] =
+    FILE_PATH_LITERAL(" Channel IDs");
 
 // The default URL prefix where browser fetches chunk updates, hashes,
 // and reports safe browsing hits and malware details.
@@ -105,6 +113,11 @@
       SafeBrowsingService::GetBaseFilename().value() + kCookiesFile);
 }
 
+base::FilePath ChannelIDFilePath() {
+  return base::FilePath(SafeBrowsingService::GetBaseFilename().value() +
+                        kChannelIDFile);
+}
+
 }  // namespace
 
 class SafeBrowsingURLRequestContextGetter
@@ -135,6 +148,10 @@
   std::unique_ptr<net::URLRequestContext> safe_browsing_request_context_;
 
   scoped_refptr<base::SingleThreadTaskRunner> network_task_runner_;
+
+  std::unique_ptr<net::ChannelIDService> channel_id_service_;
+  std::unique_ptr<net::HttpNetworkSession> http_network_session_;
+  std::unique_ptr<net::HttpTransactionFactory> http_transaction_factory_;
 };
 
 SafeBrowsingURLRequestContextGetter::SafeBrowsingURLRequestContextGetter(
@@ -166,17 +183,36 @@
             nullptr));
     safe_browsing_request_context_->set_cookie_store(
         safe_browsing_cookie_store_.get());
-    // The above cookie store will persist cookies, but the ChannelIDService in
-    // the system request context is ephemeral, which could lead to losing the
-    // keys that cookies are bound to. Since this is only used for safe
-    // browsing, any cookie bindings don't matter.
-    //
-    // For crbug.com/548423, the channel ID store and cookie store used for a
-    // request are being tracked to see if an ephemeral channel ID store is used
-    // with a persistent cookie store (which apart from here would be a bug).
-    // The following line tells that tracking to ignore the mismatch from this
-    // URLRequestContext.
-    safe_browsing_request_context_->set_has_known_mismatched_cookie_store();
+
+    // Set up the ChannelIDService
+    scoped_refptr<net::SQLiteChannelIDStore> channel_id_db =
+        new net::SQLiteChannelIDStore(
+            ChannelIDFilePath(),
+            BrowserThread::GetBlockingPool()->GetSequencedTaskRunner(
+                base::SequencedWorkerPool::GetSequenceToken()));
+    channel_id_service_.reset(new net::ChannelIDService(
+        new net::DefaultChannelIDStore(channel_id_db.get()),
+        base::WorkerPool::GetTaskRunner(true)));
+    safe_browsing_request_context_->set_channel_id_service(
+        channel_id_service_.get());
+
+    // Rebuild the HttpNetworkSession and the HttpTransactionFactory to use the
+    // new ChannelIDService.
+    if (safe_browsing_request_context_->http_transaction_factory() &&
+        safe_browsing_request_context_->http_transaction_factory()
+            ->GetSession()) {
+      net::HttpNetworkSession::Params safe_browsing_params =
+          safe_browsing_request_context_->http_transaction_factory()
+              ->GetSession()
+              ->params();
+      safe_browsing_params.channel_id_service = channel_id_service_.get();
+      http_network_session_.reset(
+          new net::HttpNetworkSession(safe_browsing_params));
+      http_transaction_factory_.reset(
+          new net::HttpNetworkLayer(http_network_session_.get()));
+      safe_browsing_request_context_->set_http_transaction_factory(
+          http_transaction_factory_.get());
+    }
   }
 
   return safe_browsing_request_context_.get();
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 5e94bece..32cb2a36 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -282,10 +282,6 @@
 
     if (enable_extensions) {
       deps += [ "//extensions/components/native_app_window" ]
-      sources +=
-          rebase_path(gypi_values.chrome_browser_ui_views_extensions_sources,
-                      ".",
-                      "//chrome")
     }
 
     if (!is_chromeos && (!is_mac || mac_views_browser)) {
diff --git a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc
index 1f78d40..89dc626 100644
--- a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc
@@ -280,6 +280,11 @@
   TaskIdToAppWindow::iterator new_active_app_it =
       task_id_to_app_window_.find(active_task_id_);
   if (new_active_app_it != task_id_to_app_window_.end()) {
+    // Activate root Arc widget if active task has been changed. This can be
+    // due creating of the new Arc app or bringing an existing app to the front.
+    if (new_active_app_it != previous_active_app_it && root_widget_)
+      root_widget_->Activate();
+
     owner()->SetItemStatus(new_active_app_it->second->shelf_id(),
                            root_widget_ && root_widget_->IsActive()
                                ? ash::STATUS_ACTIVE
diff --git a/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.mm b/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.mm
index 48bfd54..e36188d 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.mm
+++ b/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.mm
@@ -14,7 +14,6 @@
 #include "chrome/browser/extensions/api/experience_sampling_private/experience_sampling.h"
 #include "chrome/browser/extensions/extension_install_prompt_show_params.h"
 #include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/browser_finder.h"
 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.h"
 #include "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window.h"
@@ -113,7 +112,5 @@
 // static
 ExtensionInstallPrompt::ShowDialogCallback
 ExtensionInstallPrompt::GetDefaultShowDialogCallback() {
-  if (chrome::ToolkitViewsWebUIDialogsEnabled())
-    return ExtensionInstallPrompt::GetViewsShowDialogCallback();
   return base::Bind(&ShowExtensionInstallDialogImpl);
 }
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
index 23adb22..b8abfecd 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
@@ -88,6 +88,7 @@
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/color_utils.h"
 #include "ui/gfx/favicon_size.h"
+#include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/gfx/scoped_canvas.h"
 #include "ui/gfx/text_constants.h"
@@ -189,10 +190,10 @@
   return kHorizontalMargin[ui::MaterialDesignController::GetMode()];
 }
 
-gfx::Size CalculateInkDropSize(const gfx::Size& button_size) {
-  gfx::Size ink_drop_size(button_size);
-  ink_drop_size.Enlarge(0, -2);
-  return ink_drop_size;
+gfx::Rect CalculateInkDropBounds(const gfx::Size& size) {
+  gfx::Rect ink_drop_bounds(size);
+  ink_drop_bounds.Inset(0, 1);
+  return ink_drop_bounds;
 }
 
 // BookmarkButtonBase -----------------------------------------------
@@ -240,16 +241,17 @@
   std::unique_ptr<views::InkDropAnimation> CreateInkDropAnimation()
       const override {
     return base::WrapUnique(new views::FloodFillInkDropAnimation(
-        CalculateInkDropSize(size()), GetInkDropCenter(),
+        CalculateInkDropBounds(size()), GetInkDropCenter(),
         GetInkDropBaseColor()));
   }
 
   std::unique_ptr<views::InkDropHover> CreateInkDropHover() const override {
     if (!ShouldShowInkDropHover())
       return nullptr;
-    return base::WrapUnique(
-        new views::InkDropHover(CalculateInkDropSize(size()), 0,
-                                GetInkDropCenter(), GetInkDropBaseColor()));
+
+    const gfx::Rect bounds = CalculateInkDropBounds(size());
+    return base::WrapUnique(new views::InkDropHover(
+        bounds.size(), 0, bounds.CenterPoint(), GetInkDropBaseColor()));
   }
 
   SkColor GetInkDropBaseColor() const override {
@@ -341,16 +343,17 @@
   std::unique_ptr<views::InkDropAnimation> CreateInkDropAnimation()
       const override {
     return base::WrapUnique(new views::FloodFillInkDropAnimation(
-        CalculateInkDropSize(size()), GetInkDropCenter(),
+        CalculateInkDropBounds(size()), GetInkDropCenter(),
         GetInkDropBaseColor()));
   }
 
   std::unique_ptr<views::InkDropHover> CreateInkDropHover() const override {
     if (!ShouldShowInkDropHover())
       return nullptr;
-    return base::WrapUnique(
-        new views::InkDropHover(CalculateInkDropSize(size()), 0,
-                                GetInkDropCenter(), GetInkDropBaseColor()));
+
+    const gfx::Rect bounds = CalculateInkDropBounds(size());
+    return base::WrapUnique(new views::InkDropHover(
+        bounds.size(), 0, bounds.CenterPoint(), GetInkDropBaseColor()));
   }
 
   SkColor GetInkDropBaseColor() const override {
diff --git a/chrome/browser/ui/views/download/download_item_view_md.cc b/chrome/browser/ui/views/download/download_item_view_md.cc
index 66d4394..f2c6bbf 100644
--- a/chrome/browser/ui/views/download/download_item_view_md.cc
+++ b/chrome/browser/ui/views/download/download_item_view_md.cc
@@ -476,7 +476,7 @@
 std::unique_ptr<views::InkDropAnimation>
 DownloadItemViewMd::CreateInkDropAnimation() const {
   return base::WrapUnique(new views::FloodFillInkDropAnimation(
-      size(), ink_drop_delegate_.last_ink_drop_location(),
+      GetLocalBounds(), ink_drop_delegate_.last_ink_drop_location(),
       color_utils::DeriveDefaultIconColor(GetTextColor())));
 }
 
@@ -835,6 +835,10 @@
   if (complete_animation_.get() && complete_animation_->is_animating())
     complete_animation_->End();
 
+  // Don't show the ripple for right clicks.
+  if (!active_event)
+    return;
+
   ink_drop_delegate_.set_last_ink_drop_location(event.location());
   ink_drop_delegate_.OnAction(views::InkDropState::ACTION_PENDING);
 }
diff --git a/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc b/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc
index e72f60e..59e8e5c 100644
--- a/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc
+++ b/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc
@@ -771,19 +771,8 @@
   arrow_toggle_->SetImage(views::Button::STATE_NORMAL, &icon);
 }
 
-// On Mac, GetViewsShowDialogCallback is defined in Cocoa code.
-#if !defined(OS_MACOSX)
 // static
 ExtensionInstallPrompt::ShowDialogCallback
 ExtensionInstallPrompt::GetDefaultShowDialogCallback() {
   return base::Bind(&ShowExtensionInstallDialogImpl);
 }
-#endif
-
-#if defined(OS_MACOSX)
-// static
-ExtensionInstallPrompt::ShowDialogCallback
-ExtensionInstallPrompt::GetViewsShowDialogCallback() {
-  return base::Bind(&ShowExtensionInstallDialogImpl);
-}
-#endif
diff --git a/chrome/browser/ui/webui/popular_sites_internals_message_handler.cc b/chrome/browser/ui/webui/popular_sites_internals_message_handler.cc
index d6a1c3bce..9534044 100644
--- a/chrome/browser/ui/webui/popular_sites_internals_message_handler.cc
+++ b/chrome/browser/ui/webui/popular_sites_internals_message_handler.cc
@@ -14,6 +14,7 @@
 #include "base/values.h"
 #include "chrome/browser/android/ntp/popular_sites.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "components/url_formatter/url_fixer.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/web_ui.h"
@@ -55,8 +56,12 @@
 
   std::string country;
   std::string version;
+  Profile* profile = Profile::FromWebUI(web_ui());
   popular_sites_.reset(new PopularSites(
-      Profile::FromWebUI(web_ui()), country, version, false,
+      profile->GetPrefs(),
+      TemplateURLServiceFactory::GetForProfile(profile),
+      profile->GetRequestContext(),
+      country, version, false,
       base::Bind(&PopularSitesInternalsMessageHandler::OnPopularSitesAvailable,
                  base::Unretained(this), false)));
 }
@@ -64,6 +69,7 @@
 void PopularSitesInternalsMessageHandler::HandleDownload(
     const base::ListValue* args) {
   DCHECK_EQ(3u, args->GetSize());
+  Profile* profile = Profile::FromWebUI(web_ui());
   auto callback =
       base::Bind(&PopularSitesInternalsMessageHandler::OnPopularSitesAvailable,
                  base::Unretained(this), true);
@@ -72,7 +78,9 @@
   args->GetString(0, &url);
   if (!url.empty()) {
     popular_sites_.reset(new PopularSites(
-        Profile::FromWebUI(web_ui()),
+        profile->GetPrefs(),
+        TemplateURLServiceFactory::GetForProfile(profile),
+        profile->GetRequestContext(),
         url_formatter::FixupURL(url, std::string()), callback));
     return;
   }
@@ -80,8 +88,11 @@
   args->GetString(1, &country);
   std::string version;
   args->GetString(2, &version);
-  popular_sites_.reset(new PopularSites(Profile::FromWebUI(web_ui()), country,
-                                        version, true, callback));
+  popular_sites_.reset(new PopularSites(
+      profile->GetPrefs(),
+      TemplateURLServiceFactory::GetForProfile(profile),
+      profile->GetRequestContext(),
+      country, version, true, callback));
 }
 
 void PopularSitesInternalsMessageHandler::HandleViewJson(
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi
index 4bb431c..670959c 100644
--- a/chrome/chrome_browser_ui.gypi
+++ b/chrome/chrome_browser_ui.gypi
@@ -2531,9 +2531,6 @@
       'browser/ui/views/website_settings/permissions_bubble_view.cc',
       'browser/ui/views/website_settings/permissions_bubble_view.h',
     ],
-    'chrome_browser_ui_views_extensions_sources': [
-      'browser/ui/views/extensions/extension_install_dialog_view.cc',
-    ],
     'chrome_browser_ui_views_extensions_non_mac_sources': [
       'browser/ui/views/extensions/bookmark_app_confirmation_view.cc',
       'browser/ui/views/extensions/bookmark_app_confirmation_view.h',
@@ -2547,6 +2544,7 @@
       'browser/ui/views/extensions/extension_dialog.h',
       'browser/ui/views/extensions/extension_dialog_observer.cc',
       'browser/ui/views/extensions/extension_dialog_observer.h',
+      'browser/ui/views/extensions/extension_install_dialog_view.cc',
       'browser/ui/views/extensions/extension_installed_bubble_view.cc',
       'browser/ui/views/extensions/extension_popup.cc',
       'browser/ui/views/extensions/extension_popup.h',
@@ -3089,7 +3087,6 @@
               'dependencies': [
                 '<(DEPTH)/extensions/components/extensions_components.gyp:native_app_window',
               ],
-              'sources': [ '<@(chrome_browser_ui_views_extensions_sources)' ]
             }],
           ],
         }],
diff --git a/components/cronet/android/java/src/org/chromium/net/CronetLibraryLoader.java b/components/cronet/android/java/src/org/chromium/net/CronetLibraryLoader.java
index 0ce0b5430..3522c6b 100644
--- a/components/cronet/android/java/src/org/chromium/net/CronetLibraryLoader.java
+++ b/components/cronet/android/java/src/org/chromium/net/CronetLibraryLoader.java
@@ -34,7 +34,9 @@
             if (sInitTaskPosted) {
                 return;
             }
+            ContextUtils.initApplicationContext(context.getApplicationContext());
             builder.loadLibrary();
+            ContextUtils.initApplicationContextForNative();
             if (!Version.CRONET_VERSION.equals(nativeGetCronetVersion())) {
                 throw new RuntimeException(String.format(
                       "Expected Cronet version number %s, "
@@ -44,9 +46,9 @@
             }
             Log.i(TAG, "Cronet version: %s, arch: %s",
                     Version.CRONET_VERSION, System.getProperty("os.arch"));
-            ContextUtils.initApplicationContext(context.getApplicationContext());
             // Init native Chromium CronetEngine on Main UI thread.
             Runnable task = new Runnable() {
+                @Override
                 public void run() {
                     initOnMainThread(context);
                 }
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java
index 5353b8a..6807d80 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java
@@ -1112,6 +1112,7 @@
 
     @SmallTest
     @Feature({"Cronet"})
+    @OnlyRunNativeCronet
     public void testSkipLibraryLoading() throws Exception {
         CronetEngine.Builder builder = new CronetEngine.Builder(getContext());
         TestBadLibraryLoader loader = new TestBadLibraryLoader();
diff --git a/components/offline_pages/offline_page_model.cc b/components/offline_pages/offline_page_model.cc
index f7260a6c..66d8c9ec 100644
--- a/components/offline_pages/offline_page_model.cc
+++ b/components/offline_pages/offline_page_model.cc
@@ -294,6 +294,27 @@
   callback.Run(has_pages);
 }
 
+void OfflinePageModel::CheckPagesExistOffline(
+    const std::set<GURL>& urls,
+    const CheckPagesExistOfflineCallback& callback) {
+  RunWhenLoaded(
+      base::Bind(&OfflinePageModel::CheckPagesExistOfflineAfterLoadDone,
+                 weak_ptr_factory_.GetWeakPtr(), urls, callback));
+}
+
+void OfflinePageModel::CheckPagesExistOfflineAfterLoadDone(
+    const std::set<GURL>& urls,
+    const CheckPagesExistOfflineCallback& callback) {
+  DCHECK(is_loaded_);
+  CheckPagesExistOfflineResult result;
+  for (const auto& id_page_pair : offline_pages_) {
+    auto iter = urls.find(id_page_pair.second.url);
+    if (iter != urls.end())
+      result.insert(*iter);
+  }
+  callback.Run(result);
+}
+
 void OfflinePageModel::GetAllPages(const GetAllPagesCallback& callback) {
   if (!is_loaded_) {
     delayed_tasks_.push_back(
diff --git a/components/offline_pages/offline_page_model.h b/components/offline_pages/offline_page_model.h
index 3579791..35084369 100644
--- a/components/offline_pages/offline_page_model.h
+++ b/components/offline_pages/offline_page_model.h
@@ -9,6 +9,7 @@
 
 #include <map>
 #include <memory>
+#include <set>
 #include <vector>
 
 #include "base/callback.h"
@@ -123,10 +124,13 @@
   };
 
   typedef std::vector<OfflinePageItem> GetAllPagesResult;
+  typedef std::set<GURL> CheckPagesExistOfflineResult;
 
   typedef base::Callback<void(SavePageResult, int64_t)> SavePageCallback;
   typedef base::Callback<void(DeletePageResult)> DeletePageCallback;
   typedef base::Callback<void(const GetAllPagesResult&)> GetAllPagesCallback;
+  typedef base::Callback<void(const CheckPagesExistOfflineResult&)>
+      CheckPagesExistOfflineCallback;
   typedef base::Callback<void(bool)> HasPagesCallback;
 
   // Generates a new offline id
@@ -179,6 +183,11 @@
   void HasPages(const std::string& name_space,
                 const HasPagesCallback& callback);
 
+  // Returns via callback all GURLs in |urls| that are equal to the online URL
+  // of any offline page.
+  void CheckPagesExistOffline(const std::set<GURL>& urls,
+                              const CheckPagesExistOfflineCallback& callback);
+
   // Gets all available offline pages. Requires that the model is loaded.
   void GetAllPages(const GetAllPagesCallback& callback);
 
@@ -237,6 +246,9 @@
   void OnEnsureArchivesDirCreatedDone();
 
   void GetAllPagesAfterLoadDone(const GetAllPagesCallback& callback);
+  void CheckPagesExistOfflineAfterLoadDone(
+      const std::set<GURL>& urls,
+      const CheckPagesExistOfflineCallback& callback);
 
   // Callback for checking whether we have offline pages.
   void HasPagesAfterLoadDone(const std::string& name_space,
diff --git a/components/offline_pages/offline_page_model_unittest.cc b/components/offline_pages/offline_page_model_unittest.cc
index b8d7e2f..d6a8435 100644
--- a/components/offline_pages/offline_page_model_unittest.cc
+++ b/components/offline_pages/offline_page_model_unittest.cc
@@ -30,6 +30,8 @@
 using SavePageResult = offline_pages::OfflinePageModel::SavePageResult;
 using DeletePageResult = offline_pages::OfflinePageModel::DeletePageResult;
 using GetAllPagesResult = offline_pages::OfflinePageModel::GetAllPagesResult;
+using CheckPagesExistOfflineResult =
+    offline_pages::OfflinePageModel::CheckPagesExistOfflineResult;
 
 namespace offline_pages {
 
@@ -77,6 +79,7 @@
   void OnSavePageDone(SavePageResult result, int64_t offline_id);
   void OnDeletePageDone(DeletePageResult result);
   void OnHasPagesDone(bool result);
+  void OnCheckPagesExistOfflineDone(const CheckPagesExistOfflineResult& result);
   void OnClearAllDone();
 
   // OfflinePageMetadataStore callbacks.
@@ -115,6 +118,7 @@
   }
 
   bool HasPages(std::string name_space);
+  CheckPagesExistOfflineResult CheckPagesExistOffline(std::set<GURL>);
 
   OfflinePageModel* model() { return model_.get(); }
 
@@ -148,6 +152,7 @@
   int64_t last_deleted_offline_id_;
   ClientId last_deleted_client_id_;
   bool last_has_pages_result_;
+  CheckPagesExistOfflineResult last_pages_exist_result_;
 };
 
 OfflinePageModelTest::OfflinePageModelTest()
@@ -213,6 +218,11 @@
   last_has_pages_result_ = result;
 }
 
+void OfflinePageModelTest::OnCheckPagesExistOfflineDone(
+    const CheckPagesExistOfflineResult& result) {
+  last_pages_exist_result_ = result;
+}
+
 void OfflinePageModelTest::OnClearAllDone() {
   PumpLoop();
 }
@@ -260,6 +270,7 @@
   last_save_result_ = SavePageResult::CANCELLED;
   last_delete_result_ = DeletePageResult::CANCELLED;
   last_archiver_path_.clear();
+  last_pages_exist_result_.clear();
 }
 
 OfflinePageTestStore* OfflinePageModelTest::GetStore() {
@@ -290,6 +301,15 @@
   return all_pages_;
 }
 
+CheckPagesExistOfflineResult OfflinePageModelTest::CheckPagesExistOffline(
+    std::set<GURL> pages) {
+  model()->CheckPagesExistOffline(
+      pages, base::Bind(&OfflinePageModelTest::OnCheckPagesExistOfflineDone,
+                        AsWeakPtr()));
+  PumpLoop();
+  return last_pages_exist_result_;
+}
+
 bool OfflinePageModelTest::HasPages(std::string name_space) {
   model()->HasPages(
       name_space,
@@ -750,6 +770,22 @@
   EXPECT_FALSE(page);
 }
 
+TEST_F(OfflinePageModelTest, CheckPagesExistOffline) {
+  SavePage(kTestUrl, kTestClientId1);
+  SavePage(kTestUrl2, kTestClientId2);
+
+  std::set<GURL> input;
+  input.insert(kTestUrl);
+  input.insert(kTestUrl2);
+  input.insert(kTestUrl3);
+
+  CheckPagesExistOfflineResult existing_pages = CheckPagesExistOffline(input);
+  EXPECT_EQ(2U, existing_pages.size());
+  EXPECT_NE(existing_pages.end(), existing_pages.find(kTestUrl));
+  EXPECT_NE(existing_pages.end(), existing_pages.find(kTestUrl2));
+  EXPECT_EQ(existing_pages.end(), existing_pages.find(kTestUrl3));
+}
+
 // Test that model returns pages that are older than 30 days as candidates for
 // clean up, hence the numbers in time delta.
 TEST_F(OfflinePageModelTest, GetPagesToCleanUp) {
diff --git a/components/page_load_metrics/renderer/metrics_render_frame_observer.cc b/components/page_load_metrics/renderer/metrics_render_frame_observer.cc
index aa14692..ee1cc6c 100644
--- a/components/page_load_metrics/renderer/metrics_render_frame_observer.cc
+++ b/components/page_load_metrics/renderer/metrics_render_frame_observer.cc
@@ -65,8 +65,10 @@
   // non-null, we will send metrics for the current page at some later time, as
   // those metrics become available.
   if (ShouldSendMetrics()) {
+    PageLoadTiming timing(GetTiming());
+    DCHECK(!timing.navigation_start.is_null());
     page_timing_metrics_sender_.reset(
-        new PageTimingMetricsSender(this, routing_id(), CreateTimer()));
+        new PageTimingMetricsSender(this, routing_id(), CreateTimer(), timing));
   }
 }
 
diff --git a/components/page_load_metrics/renderer/metrics_render_frame_observer_unittest.cc b/components/page_load_metrics/renderer/metrics_render_frame_observer_unittest.cc
index e01ac94..f007571 100644
--- a/components/page_load_metrics/renderer/metrics_render_frame_observer_unittest.cc
+++ b/components/page_load_metrics/renderer/metrics_render_frame_observer_unittest.cc
@@ -81,9 +81,9 @@
   NiceMock<MockMetricsRenderFrameObserver> observer;
   base::MockTimer* mock_timer = new base::MockTimer(false, false);
   observer.set_mock_timer(base::WrapUnique(mock_timer));
-  observer.DidCommitProvisionalLoad(true, false);
 
   EXPECT_CALL(observer, GetTiming()).WillRepeatedly(Return(PageLoadTiming()));
+
   observer.DidChangePerformanceTiming();
   ASSERT_FALSE(mock_timer->IsRunning());
 }
@@ -95,10 +95,15 @@
   NiceMock<MockMetricsRenderFrameObserver> observer;
   base::MockTimer* mock_timer = new base::MockTimer(false, false);
   observer.set_mock_timer(base::WrapUnique(mock_timer));
-  observer.DidCommitProvisionalLoad(true, false);
 
   PageLoadTiming timing;
   timing.navigation_start = nav_start;
+  EXPECT_CALL(observer, GetTiming()).WillRepeatedly(Return(timing));
+  observer.DidCommitProvisionalLoad(true, false);
+  EXPECT_CALL(*observer.ipc_interceptor(),
+              OnTimingUpdated(timing, PageLoadMetadata()));
+  mock_timer->Fire();
+
   timing.first_layout = first_layout;
   EXPECT_CALL(observer, GetTiming()).WillRepeatedly(Return(timing));
 
@@ -118,10 +123,15 @@
   NiceMock<MockMetricsRenderFrameObserver> observer;
   base::MockTimer* mock_timer = new base::MockTimer(false, false);
   observer.set_mock_timer(base::WrapUnique(mock_timer));
-  observer.DidCommitProvisionalLoad(true, false);
 
   PageLoadTiming timing;
   timing.navigation_start = nav_start;
+  EXPECT_CALL(observer, GetTiming()).WillRepeatedly(Return(timing));
+  observer.DidCommitProvisionalLoad(true, false);
+  EXPECT_CALL(*observer.ipc_interceptor(),
+              OnTimingUpdated(timing, PageLoadMetadata()));
+  mock_timer->Fire();
+
   timing.first_layout = first_layout;
   timing.dom_content_loaded_event_start = dom_event;
   EXPECT_CALL(observer, GetTiming()).WillRepeatedly(Return(timing));
@@ -165,10 +175,15 @@
   NiceMock<MockMetricsRenderFrameObserver> observer;
   base::MockTimer* mock_timer = new base::MockTimer(false, false);
   observer.set_mock_timer(base::WrapUnique(mock_timer));
-  observer.DidCommitProvisionalLoad(true, false);
 
   PageLoadTiming timing;
   timing.navigation_start = nav_start;
+  EXPECT_CALL(observer, GetTiming()).WillRepeatedly(Return(timing));
+  observer.DidCommitProvisionalLoad(true, false);
+  EXPECT_CALL(*observer.ipc_interceptor(),
+              OnTimingUpdated(timing, PageLoadMetadata()));
+  mock_timer->Fire();
+
   timing.first_layout = first_layout;
   timing.dom_content_loaded_event_start = dom_event;
   timing.load_event_start = load_event;
@@ -189,15 +204,23 @@
   base::TimeDelta load_event_2 = base::TimeDelta::FromMillisecondsD(20);
   PageLoadTiming timing_2;
   timing_2.navigation_start = nav_start_2;
-  timing_2.first_layout = first_layout_2;
-  timing_2.dom_content_loaded_event_start = dom_event_2;
-  timing_2.load_event_start = load_event_2;
 
   base::MockTimer* mock_timer2 = new base::MockTimer(false, false);
   observer.set_mock_timer(base::WrapUnique(mock_timer2));
+
+  EXPECT_CALL(observer, GetTiming()).WillRepeatedly(Return(timing_2));
   observer.DidCommitProvisionalLoad(true, false);
   EXPECT_CALL(*observer.ipc_interceptor(),
-              OnTimingUpdated(timing, PageLoadMetadata()));
+              OnTimingUpdated(timing_2, PageLoadMetadata()));
+  mock_timer2->Fire();
+
+  timing_2.first_layout = first_layout_2;
+  timing_2.dom_content_loaded_event_start = dom_event_2;
+  timing_2.load_event_start = load_event_2;
+  EXPECT_CALL(observer, GetTiming()).WillRepeatedly(Return(timing_2));
+
+  EXPECT_CALL(*observer.ipc_interceptor(),
+              OnTimingUpdated(timing_2, PageLoadMetadata()));
   observer.DidChangePerformanceTiming();
   mock_timer2->Fire();
 }
diff --git a/components/page_load_metrics/renderer/page_timing_metrics_sender.cc b/components/page_load_metrics/renderer/page_timing_metrics_sender.cc
index 2a649191..5572461 100644
--- a/components/page_load_metrics/renderer/page_timing_metrics_sender.cc
+++ b/components/page_load_metrics/renderer/page_timing_metrics_sender.cc
@@ -15,17 +15,23 @@
 namespace page_load_metrics {
 
 namespace {
+const int kInitialTimerDelayMillis = 50;
 const int kTimerDelayMillis = 1000;
 }  // namespace
 
 PageTimingMetricsSender::PageTimingMetricsSender(
     IPC::Sender* ipc_sender,
     int routing_id,
-    std::unique_ptr<base::Timer> timer)
+    std::unique_ptr<base::Timer> timer,
+    const PageLoadTiming& initial_timing)
     : ipc_sender_(ipc_sender),
       routing_id_(routing_id),
       timer_(std::move(timer)),
-      metadata_(PageLoadMetadata()) {}
+      last_timing_(initial_timing),
+      metadata_(PageLoadMetadata()) {
+  // Send an initial IPC relatively early to help track aborts.
+  EnsureSendTimer(kInitialTimerDelayMillis);
+}
 
 // On destruction, we want to send any data we have if we have a timer
 // currently running (and thus are talking to a browser process)
@@ -41,7 +47,7 @@
   if (behavior & metadata_.behavior_flags)
     return;
   metadata_.behavior_flags |= behavior;
-  EnsureSendTimer();
+  EnsureSendTimer(kTimerDelayMillis);
 }
 
 void PageTimingMetricsSender::Send(const PageLoadTiming& timing) {
@@ -57,13 +63,13 @@
   }
 
   last_timing_ = timing;
-  EnsureSendTimer();
+  EnsureSendTimer(kTimerDelayMillis);
 }
 
-void PageTimingMetricsSender::EnsureSendTimer() {
+void PageTimingMetricsSender::EnsureSendTimer(int delay) {
   if (!timer_->IsRunning())
     timer_->Start(
-        FROM_HERE, base::TimeDelta::FromMilliseconds(kTimerDelayMillis),
+        FROM_HERE, base::TimeDelta::FromMilliseconds(delay),
         base::Bind(&PageTimingMetricsSender::SendNow, base::Unretained(this)));
 }
 
diff --git a/components/page_load_metrics/renderer/page_timing_metrics_sender.h b/components/page_load_metrics/renderer/page_timing_metrics_sender.h
index 37d16fbc..1cdfb73 100644
--- a/components/page_load_metrics/renderer/page_timing_metrics_sender.h
+++ b/components/page_load_metrics/renderer/page_timing_metrics_sender.h
@@ -28,7 +28,8 @@
  public:
   PageTimingMetricsSender(IPC::Sender* ipc_sender,
                           int routing_id,
-                          std::unique_ptr<base::Timer> timer);
+                          std::unique_ptr<base::Timer> timer,
+                          const PageLoadTiming& initial_timing);
   ~PageTimingMetricsSender();
 
   void DidObserveLoadingBehavior(blink::WebLoadingBehaviorFlag behavior);
@@ -38,7 +39,7 @@
   base::Timer* timer() const { return timer_.get(); }
 
  private:
-  void EnsureSendTimer();
+  void EnsureSendTimer(int delay);
   void SendNow();
 
   IPC::Sender* const ipc_sender_;
diff --git a/components/page_load_metrics/renderer/page_timing_metrics_sender_unittest.cc b/components/page_load_metrics/renderer/page_timing_metrics_sender_unittest.cc
index 6a3f9b25..83993d6 100644
--- a/components/page_load_metrics/renderer/page_timing_metrics_sender_unittest.cc
+++ b/components/page_load_metrics/renderer/page_timing_metrics_sender_unittest.cc
@@ -35,11 +35,13 @@
 // MockTimer instance.
 class TestPageTimingMetricsSender : public PageTimingMetricsSender {
  public:
-  explicit TestPageTimingMetricsSender(IPC::Sender* ipc_sender)
+  explicit TestPageTimingMetricsSender(IPC::Sender* ipc_sender,
+                                       const PageLoadTiming& initial_timing)
       : PageTimingMetricsSender(
             ipc_sender,
             MSG_ROUTING_NONE,
-            std::unique_ptr<base::Timer>(new base::MockTimer(false, false))) {}
+            std::unique_ptr<base::Timer>(new base::MockTimer(false, false)),
+            initial_timing) {}
 
   base::MockTimer* mock_timer() const {
     return reinterpret_cast<base::MockTimer*>(timer());
@@ -48,7 +50,8 @@
 
 class PageTimingMetricsSenderTest : public testing::Test {
  public:
-  PageTimingMetricsSenderTest() : metrics_sender_(&mock_ipc_sender_) {}
+  PageTimingMetricsSenderTest()
+      : metrics_sender_(&mock_ipc_sender_, PageLoadTiming()) {}
 
  protected:
   testing::StrictMock<MockIPCSender> mock_ipc_sender_;
@@ -133,16 +136,14 @@
 TEST_F(PageTimingMetricsSenderTest, SendIPCOnDestructor) {
   PageLoadTiming timing;
   timing.navigation_start = base::Time::FromDoubleT(10);
-  {
-    // This test wants to verify behavior in the PageTimingMetricsSender
-    // destructor, so we create our own instance to make it go out of scope
-    // before the end of the test body.
-    TestPageTimingMetricsSender sender(&mock_ipc_sender_);
+  timing.first_layout = base::TimeDelta::FromMilliseconds(10);
 
-    sender.Send(timing);
-    EXPECT_CALL(mock_ipc_sender_, OnTimingUpdated(timing, PageLoadMetadata()));
-    ASSERT_TRUE(sender.mock_timer()->IsRunning());
-  }
+  // This test wants to verify behavior in the PageTimingMetricsSender
+  // destructor, the EXPECT_CALL will be verified when the test tears down and
+  // |metrics_sender_| goes out of scope.
+  metrics_sender_.Send(timing);
+  EXPECT_CALL(mock_ipc_sender_, OnTimingUpdated(timing, PageLoadMetadata()));
+  ASSERT_TRUE(metrics_sender_.mock_timer()->IsRunning());
 }
 
 }  // namespace page_load_metrics
diff --git a/components/resource_provider/android/android_hooks.cc b/components/resource_provider/android/android_hooks.cc
index 4cf2687..b312e1af 100644
--- a/components/resource_provider/android/android_hooks.cc
+++ b/components/resource_provider/android/android_hooks.cc
@@ -46,7 +46,6 @@
 extern "C" JNI_EXPORT void InitApplicationContext(
     const base::android::JavaRef<jobject>& context) {
   JNIEnv* env = base::android::AttachCurrentThread();
-  base::android::InitApplicationContext(env, context);
   resource_provider::Java_Main_init(
       env, base::android::GetApplicationContext());
 }
diff --git a/components/resource_provider/android/java/org/chromium/resource_provider/Main.java b/components/resource_provider/android/java/org/chromium/resource_provider/Main.java
index 6395262..a65e6917 100644
--- a/components/resource_provider/android/java/org/chromium/resource_provider/Main.java
+++ b/components/resource_provider/android/java/org/chromium/resource_provider/Main.java
@@ -6,6 +6,7 @@
 
 import android.content.Context;
 
+import org.chromium.base.ContextUtils;
 import org.chromium.base.PathUtils;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
@@ -22,6 +23,7 @@
     @SuppressWarnings("unused")
     @CalledByNative
     private static void init(Context context) {
+        ContextUtils.initApplicationContext(context.getApplicationContext());
         PathUtils.setPrivateDataDirectorySuffix(PRIVATE_DATA_DIRECTORY_SUFFIX, context);
     }
 }
diff --git a/components/test_runner/layout_test_runtime_flags.cc b/components/test_runner/layout_test_runtime_flags.cc
index 63e3310..c9d530f 100644
--- a/components/test_runner/layout_test_runtime_flags.cc
+++ b/components/test_runner/layout_test_runtime_flags.cc
@@ -58,6 +58,8 @@
 
   set_stay_on_page_after_handling_before_unload(false);
 
+  set_have_top_loading_frame(false);
+
   // No need to report the initial state - only the future delta is important.
   tracked_dictionary().ResetChangeTracking();
 }
diff --git a/components/test_runner/layout_test_runtime_flags.h b/components/test_runner/layout_test_runtime_flags.h
index 0a4355b..78c8cbf 100644
--- a/components/test_runner/layout_test_runtime_flags.h
+++ b/components/test_runner/layout_test_runtime_flags.h
@@ -158,6 +158,12 @@
   DEFINE_BOOL_LAYOUT_TEST_RUNTIME_FLAG(
       stay_on_page_after_handling_before_unload)
 
+  // Indicates if the test already tracks a top loading frame (in any of the
+  // renderer processes).  This flag is trying to prevent different renderer
+  // processes from tracking different top loading frames (i.e. main frame in
+  // one renderer and an OOPIF in another renderer).
+  DEFINE_BOOL_LAYOUT_TEST_RUNTIME_FLAG(have_top_loading_frame)
+
 #undef DEFINE_BOOL_LAYOUT_TEST_RUNTIME_FLAG
 #undef DEFINE_STRING_LAYOUT_TEST_RUNTIME_FLAG
 
diff --git a/components/test_runner/test_runner.cc b/components/test_runner/test_runner.cc
index b668843..2d0597ab 100644
--- a/components/test_runner/test_runner.cc
+++ b/components/test_runner/test_runner.cc
@@ -1832,9 +1832,9 @@
 
 void TestRunner::ReplicateLayoutTestRuntimeFlagsChanges(
     const base::DictionaryValue& changed_values) {
-  DCHECK(test_is_running_);
-  layout_test_runtime_flags_.tracked_dictionary().ApplyUntrackedChanges(
-      changed_values);
+  if (test_is_running_)
+    layout_test_runtime_flags_.tracked_dictionary().ApplyUntrackedChanges(
+        changed_values);
 }
 
 bool TestRunner::HasCustomTextDump(std::string* custom_text_dump) const {
@@ -1944,10 +1944,12 @@
   if (!IsFramePartOfMainTestWindow(frame))
     return false;
 
-  if (top_loading_frame_)
+  if (top_loading_frame_ || layout_test_runtime_flags_.have_top_loading_frame())
     return false;
 
   top_loading_frame_ = frame;
+  layout_test_runtime_flags_.set_have_top_loading_frame(true);
+  OnLayoutTestRuntimeFlagsChanged();
   return true;
 }
 
@@ -1959,6 +1961,10 @@
     return false;
 
   top_loading_frame_ = nullptr;
+  DCHECK(layout_test_runtime_flags_.have_top_loading_frame());
+  layout_test_runtime_flags_.set_have_top_loading_frame(false);
+  OnLayoutTestRuntimeFlagsChanged();
+
   LocationChangeDone();
   return true;
 }
@@ -3127,6 +3133,8 @@
 void TestRunner::OnLayoutTestRuntimeFlagsChanged() {
   if (layout_test_runtime_flags_.tracked_dictionary().changed_values().empty())
     return;
+  if (!test_is_running_)
+    return;
 
   delegate_->OnLayoutTestRuntimeFlagsChanged(
       layout_test_runtime_flags_.tracked_dictionary().changed_values());
diff --git a/components/web_restrictions/browser/junit/src/org/chromium/components/webrestrictions/WebRestrictionsClientTest.java b/components/web_restrictions/browser/junit/src/org/chromium/components/webrestrictions/WebRestrictionsClientTest.java
index 662fbf40..0fd8756 100644
--- a/components/web_restrictions/browser/junit/src/org/chromium/components/webrestrictions/WebRestrictionsClientTest.java
+++ b/components/web_restrictions/browser/junit/src/org/chromium/components/webrestrictions/WebRestrictionsClientTest.java
@@ -41,7 +41,7 @@
 
     @Before
     public void setUp() {
-        ContextUtils.initApplicationContextForJUnitTests(Robolectric.application);
+        ContextUtils.initApplicationContextForTests(Robolectric.application);
         mTestClient = Mockito.spy(new WebRestrictionsClient());
         Mockito.doNothing().when(mTestClient).nativeNotifyWebRestrictionsChanged(anyLong());
         mProvider = Mockito.mock(ContentProvider.class);
diff --git a/content/browser/gamepad/gamepad_platform_data_fetcher_mac.h b/content/browser/gamepad/gamepad_platform_data_fetcher_mac.h
index d373fee3..1fe50c0c 100644
--- a/content/browser/gamepad/gamepad_platform_data_fetcher_mac.h
+++ b/content/browser/gamepad/gamepad_platform_data_fetcher_mac.h
@@ -60,6 +60,7 @@
   size_t GetSlotForXboxDevice(XboxController* device);
 
   void DeviceAdd(IOHIDDeviceRef device);
+  bool CheckCollection(IOHIDElementRef element);
   bool AddButtonsAndAxes(NSArray* elements, size_t slot);
   void DeviceRemove(IOHIDDeviceRef device);
   void ValueChanged(IOHIDValueRef value);
diff --git a/content/browser/gamepad/gamepad_platform_data_fetcher_mac.mm b/content/browser/gamepad/gamepad_platform_data_fetcher_mac.mm
index 4d55c55..fe77f536 100644
--- a/content/browser/gamepad/gamepad_platform_data_fetcher_mac.mm
+++ b/content/browser/gamepad/gamepad_platform_data_fetcher_mac.mm
@@ -156,6 +156,23 @@
   InstanceFromContext(context)->ValueChanged(ref);
 }
 
+bool GamepadPlatformDataFetcherMac::CheckCollection(IOHIDElementRef element) {
+  // Check that a parent collection of this element matches one of the usage
+  // numbers that we are looking for.
+  while ((element = IOHIDElementGetParent(element)) != NULL) {
+    uint32_t usage_page = IOHIDElementGetUsagePage(element);
+    uint32_t usage = IOHIDElementGetUsage(element);
+    if (usage_page == kGenericDesktopUsagePage) {
+      if (usage == kJoystickUsageNumber ||
+          usage == kGameUsageNumber ||
+          usage == kMultiAxisUsageNumber) {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
 bool GamepadPlatformDataFetcherMac::AddButtonsAndAxes(NSArray* elements,
                                                       size_t slot) {
   WebGamepad& pad = pad_state_[slot].data;
@@ -172,6 +189,9 @@
 
   for (id elem in elements) {
     IOHIDElementRef element = reinterpret_cast<IOHIDElementRef>(elem);
+    if (!CheckCollection(element))
+      continue;
+
     uint32_t usage_page = IOHIDElementGetUsagePage(element);
     uint32_t usage = IOHIDElementGetUsage(element);
     if (IOHIDElementGetType(element) == kIOHIDElementTypeInput_Button &&
@@ -202,6 +222,9 @@
     uint32_t next_index = 0;
     for (id elem in elements) {
       IOHIDElementRef element = reinterpret_cast<IOHIDElementRef>(elem);
+      if (!CheckCollection(element))
+        continue;
+
       uint32_t usage_page = IOHIDElementGetUsagePage(element);
       uint32_t usage = IOHIDElementGetUsage(element);
       if (IOHIDElementGetType(element) == kIOHIDElementTypeInput_Misc &&
diff --git a/content/browser/media/capture/aura_window_capture_machine.cc b/content/browser/media/capture/aura_window_capture_machine.cc
index 51e8d128..6aff1cbc 100644
--- a/content/browser/media/capture/aura_window_capture_machine.cc
+++ b/content/browser/media/capture/aura_window_capture_machine.cc
@@ -31,7 +31,6 @@
 #include "ui/compositor/compositor.h"
 #include "ui/compositor/dip_util.h"
 #include "ui/compositor/layer.h"
-#include "ui/gfx/screen.h"
 #include "ui/wm/public/activation_client.h"
 
 namespace content {
diff --git a/content/browser/media/capture/web_contents_video_capture_device_unittest.cc b/content/browser/media/capture/web_contents_video_capture_device_unittest.cc
index 32e4209..13367a3 100644
--- a/content/browser/media/capture/web_contents_video_capture_device_unittest.cc
+++ b/content/browser/media/capture/web_contents_video_capture_device_unittest.cc
@@ -42,10 +42,10 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/layout.h"
-#include "ui/gfx/display.h"
+#include "ui/display/display.h"
+#include "ui/display/screen.h"
 #include "ui/gfx/geometry/dip_util.h"
 #include "ui/gfx/geometry/size_conversions.h"
-#include "ui/gfx/screen.h"
 #include "ui/gfx/test/test_screen.h"
 
 namespace content {
@@ -600,8 +600,8 @@
     test_screen_.display()->set_bounds(gfx::Rect(0, 0, 2560, 1440));
     test_screen_.display()->set_device_scale_factor(kTestDeviceScaleFactor);
 
-    gfx::Screen::SetScreenInstance(&test_screen_);
-    ASSERT_EQ(&test_screen_, gfx::Screen::GetScreen());
+    display::Screen::SetScreenInstance(&test_screen_);
+    ASSERT_EQ(&test_screen_, display::Screen::GetScreen());
 
     // TODO(nick): Sadness and woe! Much "mock-the-world" boilerplate could be
     // eliminated here, if only we could use RenderViewHostTestHarness. The
@@ -659,7 +659,7 @@
     render_view_host_factory_.reset();
     render_process_host_factory_.reset();
 
-    gfx::Screen::SetScreenInstance(nullptr);
+    display::Screen::SetScreenInstance(nullptr);
   }
 
   // Accessors.
diff --git a/content/browser/renderer_host/dip_util.cc b/content/browser/renderer_host/dip_util.cc
index 225d17b..3d20622 100644
--- a/content/browser/renderer_host/dip_util.cc
+++ b/content/browser/renderer_host/dip_util.cc
@@ -6,7 +6,6 @@
 
 #include "content/public/browser/render_widget_host_view.h"
 #include "ui/base/layout.h"
-#include "ui/gfx/display.h"
 #include "ui/gfx/geometry/dip_util.h"
 #include "ui/gfx/geometry/point.h"
 #include "ui/gfx/geometry/point_conversions.h"
@@ -14,7 +13,6 @@
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/geometry/size_conversions.h"
-#include "ui/gfx/screen.h"
 
 namespace content {
 
diff --git a/content/browser/renderer_host/input/web_input_event_unittest.cc b/content/browser/renderer_host/input/web_input_event_unittest.cc
index b05608fa..2abe1e1 100644
--- a/content/browser/renderer_host/input/web_input_event_unittest.cc
+++ b/content/browser/renderer_host/input/web_input_event_unittest.cc
@@ -6,8 +6,8 @@
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/web/WebInputEvent.h"
+#include "ui/display/display.h"
 #include "ui/events/event_constants.h"
-#include "ui/gfx/display.h"
 #include "ui/gfx/switches.h"
 
 #if defined(OS_WIN)
@@ -27,7 +27,7 @@
   if (base::win::GetVersion() < base::win::VERSION_WIN7)
     return;
 
-  gfx::Display::ResetForceDeviceScaleFactorForTesting();
+  display::Display::ResetForceDeviceScaleFactorForTesting();
 
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
   command_line->AppendSwitchASCII(switches::kForceDeviceScaleFactor, "2");
@@ -52,7 +52,7 @@
   EXPECT_EQ(100, mouse_move.globalY);
 
   command_line->AppendSwitchASCII(switches::kForceDeviceScaleFactor, "1");
-  gfx::Display::ResetForceDeviceScaleFactorForTesting();
+  display::Display::ResetForceDeviceScaleFactorForTesting();
 }
 #endif
 
diff --git a/content/browser/renderer_host/render_widget_host_unittest.cc b/content/browser/renderer_host/render_widget_host_unittest.cc
index 77515873..f3556cb 100644
--- a/content/browser/renderer_host/render_widget_host_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_unittest.cc
@@ -29,9 +29,9 @@
 #include "content/public/test/test_browser_context.h"
 #include "content/test/test_render_view_host.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/display/screen.h"
 #include "ui/events/keycodes/keyboard_codes.h"
 #include "ui/gfx/canvas.h"
-#include "ui/gfx/screen.h"
 
 #if defined(OS_ANDROID)
 #include "content/browser/renderer_host/render_widget_host_view_android.h"
@@ -464,7 +464,7 @@
 #endif
 #if defined(USE_AURA)
     screen_.reset(aura::TestScreen::Create(gfx::Size()));
-    gfx::Screen::SetScreenInstance(screen_.get());
+    display::Screen::SetScreenInstance(screen_.get());
 #endif
     host_.reset(new MockRenderWidgetHost(delegate_.get(), process_,
                                          process_->GetNextRoutingID()));
@@ -484,7 +484,7 @@
     browser_context_.reset();
 
 #if defined(USE_AURA)
-    gfx::Screen::SetScreenInstance(nullptr);
+    display::Screen::SetScreenInstance(nullptr);
     screen_.reset();
 #endif
 #if defined(USE_AURA) || defined(OS_MACOSX)
@@ -629,7 +629,7 @@
   std::unique_ptr<MockRenderWidgetHostDelegate> delegate_;
   std::unique_ptr<MockRenderWidgetHost> host_;
   std::unique_ptr<TestView> view_;
-  std::unique_ptr<gfx::Screen> screen_;
+  std::unique_ptr<display::Screen> screen_;
   bool handle_key_press_event_;
   bool handle_mouse_event_;
   double last_simulated_event_time_seconds_;
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc
index dbca7b5..5e05335 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.cc
+++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -80,16 +80,16 @@
 #include "third_party/skia/include/core/SkCanvas.h"
 #include "ui/android/window_android.h"
 #include "ui/android/window_android_compositor.h"
+#include "ui/display/display.h"
+#include "ui/display/screen.h"
 #include "ui/events/blink/blink_event_util.h"
 #include "ui/events/gesture_detection/gesture_provider_config_helper.h"
 #include "ui/events/gesture_detection/motion_event.h"
 #include "ui/gfx/android/device_display_info.h"
 #include "ui/gfx/android/java_bitmap.h"
 #include "ui/gfx/android/view_configuration.h"
-#include "ui/gfx/display.h"
 #include "ui/gfx/geometry/dip_util.h"
 #include "ui/gfx/geometry/size_conversions.h"
-#include "ui/gfx/screen.h"
 #include "ui/touch_selection/touch_selection_controller.h"
 
 namespace content {
@@ -421,7 +421,8 @@
     src_subrect = gfx::Rect(bounds);
   DCHECK_LE(src_subrect.width() + src_subrect.x(), bounds.width());
   DCHECK_LE(src_subrect.height() + src_subrect.y(), bounds.height());
-  const gfx::Display& display = gfx::Screen::GetScreen()->GetPrimaryDisplay();
+  const display::Display& display =
+      display::Screen::GetScreen()->GetPrimaryDisplay();
   float device_scale_factor = display.device_scale_factor();
   DCHECK_GT(device_scale_factor, 0);
   gfx::Size dst_size(
@@ -876,7 +877,8 @@
     callback.Run(SkBitmap(), READBACK_SURFACE_UNAVAILABLE);
     return;
   }
-  const gfx::Display& display = gfx::Screen::GetScreen()->GetPrimaryDisplay();
+  const display::Display& display =
+      display::Screen::GetScreen()->GetPrimaryDisplay();
   float device_scale_factor = display.device_scale_factor();
   gfx::Size dst_size_in_pixel =
       gfx::ConvertRectToPixel(device_scale_factor, gfx::Rect(dst_size)).size();
@@ -2007,7 +2009,8 @@
 // static
 void RenderWidgetHostViewBase::GetDefaultScreenInfo(
     blink::WebScreenInfo* results) {
-  const gfx::Display& display = gfx::Screen::GetScreen()->GetPrimaryDisplay();
+  const display::Display& display =
+      display::Screen::GetScreen()->GetPrimaryDisplay();
   results->rect = display.bounds();
   // TODO(husky): Remove any system controls from availableRect.
   results->availableRect = display.work_area();
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
index bdc85b1..e2815c2 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -76,6 +76,8 @@
 #include "ui/base/ui_base_types.h"
 #include "ui/compositor/compositor_vsync_manager.h"
 #include "ui/compositor/dip_util.h"
+#include "ui/display/display.h"
+#include "ui/display/screen.h"
 #include "ui/events/blink/blink_event_util.h"
 #include "ui/events/event.h"
 #include "ui/events/event_utils.h"
@@ -83,11 +85,9 @@
 #include "ui/events/gestures/gesture_recognizer.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/color_profile.h"
-#include "ui/gfx/display.h"
 #include "ui/gfx/geometry/dip_util.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/geometry/size_conversions.h"
-#include "ui/gfx/screen.h"
 #include "ui/gfx/skia_util.h"
 #include "ui/touch_selection/touch_selection_controller.h"
 #include "ui/wm/public/activation_client.h"
@@ -169,9 +169,10 @@
 }
 
 void GetScreenInfoForWindow(WebScreenInfo* results, aura::Window* window) {
-  gfx::Screen* screen = gfx::Screen::GetScreen();
-  const gfx::Display display = window ? screen->GetDisplayNearestWindow(window)
-                                      : screen->GetPrimaryDisplay();
+  display::Screen* screen = display::Screen::GetScreen();
+  const display::Display display = window
+                                       ? screen->GetDisplayNearestWindow(window)
+                                       : screen->GetPrimaryDisplay();
   results->rect = display.bounds();
   results->availableRect = display.work_area();
   // TODO(derat|oshima): Don't hardcode this. Get this from display object.
@@ -433,8 +434,8 @@
   if (parent_view)
     parent_view->AddChild(GetNativeView());
 
-  const gfx::Display display =
-      gfx::Screen::GetScreen()->GetDisplayNearestWindow(window_);
+  const display::Display display =
+      display::Screen::GetScreen()->GetDisplayNearestWindow(window_);
   device_scale_factor_ = display.device_scale_factor();
 }
 
@@ -486,8 +487,8 @@
 
   event_filter_for_popup_exit_.reset(new EventFilterForPopupExit(this));
 
-  const gfx::Display display =
-      gfx::Screen::GetScreen()->GetDisplayNearestWindow(window_);
+  const display::Display display =
+      display::Screen::GetScreen()->GetDisplayNearestWindow(window_);
   device_scale_factor_ = display.device_scale_factor();
 }
 
@@ -510,8 +511,8 @@
       host_tracker_.reset(new aura::WindowTracker);
       host_tracker_->Add(reference_window);
     }
-    gfx::Display display =
-        gfx::Screen::GetScreen()->GetDisplayNearestWindow(reference_window);
+    display::Display display =
+        display::Screen::GetScreen()->GetDisplayNearestWindow(reference_window);
     parent = reference_window->GetRootWindow();
     bounds = display.bounds();
   }
@@ -519,8 +520,8 @@
   Show();
   Focus();
 
-  const gfx::Display display =
-      gfx::Screen::GetScreen()->GetDisplayNearestWindow(window_);
+  const display::Display display =
+      display::Screen::GetScreen()->GetDisplayNearestWindow(window_);
   device_scale_factor_ = display.device_scale_factor();
 }
 
@@ -862,8 +863,8 @@
 
 void RenderWidgetHostViewAura::UpdateCursor(const WebCursor& cursor) {
   current_cursor_ = cursor;
-  const gfx::Display display =
-      gfx::Screen::GetScreen()->GetDisplayNearestWindow(window_);
+  const display::Display display =
+      display::Screen::GetScreen()->GetDisplayNearestWindow(window_);
   current_cursor_.SetDisplayInfo(display);
   UpdateCursorIfOverSelf();
 }
@@ -1040,8 +1041,9 @@
 
 void RenderWidgetHostViewAura::UpdateMouseLockRegion() {
   RECT window_rect =
-      gfx::Screen::GetScreen()->DIPToScreenRectInWindow(
-          window_, window_->GetBoundsInScreen()).ToRECT();
+      display::Screen::GetScreen()
+          ->DIPToScreenRectInWindow(window_, window_->GetBoundsInScreen())
+          .ToRECT();
   ::ClipCursor(&window_rect);
 }
 
@@ -1135,7 +1137,8 @@
     }
   }
 
-  bounds = gfx::Screen::GetScreen()->ScreenToDIPRectInWindow(top_level, bounds);
+  bounds =
+      display::Screen::GetScreen()->ScreenToDIPRectInWindow(top_level, bounds);
 #endif
 
   return bounds;
@@ -1688,20 +1691,19 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// RenderWidgetHostViewAura, gfx::DisplayObserver implementation:
+// RenderWidgetHostViewAura, display::DisplayObserver implementation:
 
 void RenderWidgetHostViewAura::OnDisplayAdded(
-    const gfx::Display& new_display) {
-}
+    const display::Display& new_display) {}
 
 void RenderWidgetHostViewAura::OnDisplayRemoved(
-    const gfx::Display& old_display) {
-}
+    const display::Display& old_display) {}
 
 void RenderWidgetHostViewAura::OnDisplayMetricsChanged(
-    const gfx::Display& display, uint32_t metrics) {
+    const display::Display& display,
+    uint32_t metrics) {
   // The screen info should be updated regardless of the metric change.
-  gfx::Screen* screen = gfx::Screen::GetScreen();
+  display::Screen* screen = display::Screen::GetScreen();
   if (display.id() == screen->GetDisplayNearestWindow(window_).id()) {
     UpdateScreenInfo(window_);
     current_cursor_.SetDisplayInfo(display);
@@ -1772,8 +1774,8 @@
   UpdateScreenInfo(window_);
 
   device_scale_factor_ = device_scale_factor;
-  const gfx::Display display = gfx::Screen::GetScreen()->
-      GetDisplayNearestWindow(window_);
+  const display::Display display =
+      display::Screen::GetScreen()->GetDisplayNearestWindow(window_);
   DCHECK_EQ(device_scale_factor, display.device_scale_factor());
   current_cursor_.SetDisplayInfo(display);
   SnapToPhysicalPixelBoundary();
@@ -2302,7 +2304,7 @@
     // If we lose the focus while fullscreen, close the window; Pepper Flash
     // won't do it for us (unlike NPAPI Flash). However, we do not close the
     // window if we lose the focus to a window on another display.
-    gfx::Screen* screen = gfx::Screen::GetScreen();
+    display::Screen* screen = display::Screen::GetScreen();
     bool focusing_other_display =
         gained_focus && screen->GetNumDisplays() > 1 &&
         (screen->GetDisplayNearestWindow(window_).id() !=
@@ -2360,7 +2362,7 @@
       window_->GetHost()->RemoveObserver(this);
     UnlockMouse();
     aura::client::SetTooltipText(window_, NULL);
-    gfx::Screen::GetScreen()->RemoveObserver(this);
+    display::Screen::GetScreen()->RemoveObserver(this);
 
     // This call is usually no-op since |this| object is already removed from
     // the Aura root window and we don't have a way to get an input method
@@ -2396,7 +2398,7 @@
   aura::client::SetActivationDelegate(window_, this);
   aura::client::SetFocusChangeObserver(window_, this);
   window_->set_layer_owner_delegate(delegated_frame_host_.get());
-  gfx::Screen::GetScreen()->AddObserver(this);
+  display::Screen::GetScreen()->AddObserver(this);
 }
 
 void RenderWidgetHostViewAura::UpdateCursorIfOverSelf() {
@@ -2407,7 +2409,7 @@
   if (!root_window)
     return;
 
-  gfx::Screen* screen = gfx::Screen::GetScreen();
+  display::Screen* screen = display::Screen::GetScreen();
   DCHECK(screen);
 
   gfx::Point cursor_screen_point = screen->GetCursorScreenPoint();
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h
index 494d269..bccb444 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.h
+++ b/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -38,8 +38,8 @@
 #include "ui/aura/window_tree_host_observer.h"
 #include "ui/base/ime/text_input_client.h"
 #include "ui/base/touch/selection_bound.h"
+#include "ui/display/display_observer.h"
 #include "ui/events/gestures/motion_event_aura.h"
-#include "ui/gfx/display_observer.h"
 #include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/wm/public/activation_delegate.h"
@@ -92,7 +92,7 @@
     : public RenderWidgetHostViewBase,
       public DelegatedFrameHostClient,
       public ui::TextInputClient,
-      public gfx::DisplayObserver,
+      public display::DisplayObserver,
       public aura::WindowTreeHostObserver,
       public aura::WindowDelegate,
       public aura::client::ActivationDelegate,
@@ -235,10 +235,10 @@
   bool IsEditCommandEnabled(int command_id) override;
   void SetEditCommandForNextKeyEvent(int command_id) override;
 
-  // Overridden from gfx::DisplayObserver:
-  void OnDisplayAdded(const gfx::Display& new_display) override;
-  void OnDisplayRemoved(const gfx::Display& old_display) override;
-  void OnDisplayMetricsChanged(const gfx::Display& display,
+  // Overridden from display::DisplayObserver:
+  void OnDisplayAdded(const display::Display& new_display) override;
+  void OnDisplayRemoved(const display::Display& old_display) override;
+  void OnDisplayMetricsChanged(const display::Display& display,
                                uint32_t metrics) override;
 
   // Overridden from aura::WindowDelegate:
diff --git a/content/browser/renderer_host/render_widget_host_view_base.cc b/content/browser/renderer_host/render_widget_host_view_base.cc
index cf28db2d..dd88fae 100644
--- a/content/browser/renderer_host/render_widget_host_view_base.cc
+++ b/content/browser/renderer_host/render_widget_host_view_base.cc
@@ -15,11 +15,11 @@
 #include "content/browser/renderer_host/render_widget_host_view_base_observer.h"
 #include "content/common/content_switches_internal.h"
 #include "content/public/browser/render_widget_host_view_frame_subscriber.h"
-#include "ui/gfx/display.h"
+#include "ui/display/display.h"
+#include "ui/display/screen.h"
 #include "ui/gfx/geometry/point_conversions.h"
 #include "ui/gfx/geometry/size_conversions.h"
 #include "ui/gfx/geometry/size_f.h"
-#include "ui/gfx/screen.h"
 
 namespace content {
 
@@ -38,7 +38,7 @@
       selection_text_offset_(0),
       selection_range_(gfx::Range::InvalidRange()),
       current_device_scale_factor_(0),
-      current_display_rotation_(gfx::Display::ROTATE_0),
+      current_display_rotation_(display::Display::ROTATE_0),
       pinch_zoom_enabled_(content::IsPinchToZoomEnabled()),
       renderer_frame_number_(0),
       weak_factory_(this) {}
@@ -82,8 +82,8 @@
 }
 
 gfx::Size RenderWidgetHostViewBase::GetPhysicalBackingSize() const {
-  gfx::Display display =
-      gfx::Screen::GetScreen()->GetDisplayNearestWindow(GetNativeView());
+  display::Display display =
+      display::Screen::GetScreen()->GetDisplayNearestWindow(GetNativeView());
   return gfx::ScaleToCeiledSize(GetRequestedRendererSize(),
                                 display.device_scale_factor());
 }
@@ -214,8 +214,8 @@
 }
 
 bool RenderWidgetHostViewBase::HasDisplayPropertyChanged(gfx::NativeView view) {
-  gfx::Display display =
-      gfx::Screen::GetScreen()->GetDisplayNearestWindow(view);
+  display::Display display =
+      display::Screen::GetScreen()->GetDisplayNearestWindow(view);
   if (current_display_area_ == display.work_area() &&
       current_device_scale_factor_ == display.device_scale_factor() &&
       current_display_rotation_ == display.rotation()) {
@@ -291,7 +291,7 @@
 // static
 blink::WebScreenOrientationType
 RenderWidgetHostViewBase::GetOrientationTypeForMobile(
-    const gfx::Display& display) {
+    const display::Display& display) {
   int angle = display.RotationAsDegree();
   const gfx::Rect& bounds = display.bounds();
 
@@ -324,7 +324,7 @@
 // static
 blink::WebScreenOrientationType
 RenderWidgetHostViewBase::GetOrientationTypeForDesktop(
-    const gfx::Display& display) {
+    const display::Display& display) {
   static int primary_landscape_angle = -1;
   static int primary_portrait_angle = -1;
 
diff --git a/content/browser/renderer_host/render_widget_host_view_base.h b/content/browser/renderer_host/render_widget_host_view_base.h
index b71919b..8eb96897e 100644
--- a/content/browser/renderer_host/render_widget_host_view_base.h
+++ b/content/browser/renderer_host/render_widget_host_view_base.h
@@ -31,7 +31,7 @@
 #include "third_party/WebKit/public/web/WebTextDirection.h"
 #include "ui/base/ime/text_input_mode.h"
 #include "ui/base/ime/text_input_type.h"
-#include "ui/gfx/display.h"
+#include "ui/display/display.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/gfx/range/range.h"
@@ -333,11 +333,11 @@
 
   // Compute the orientation type of the display assuming it is a mobile device.
   static blink::WebScreenOrientationType GetOrientationTypeForMobile(
-      const gfx::Display& display);
+      const display::Display& display);
 
   // Compute the orientation type of the display assuming it is a desktop.
   static blink::WebScreenOrientationType GetOrientationTypeForDesktop(
-      const gfx::Display& display);
+      const display::Display& display);
 
   virtual void GetScreenInfo(blink::WebScreenInfo* results) = 0;
   virtual bool GetScreenColorProfile(std::vector<char>* color_profile) = 0;
@@ -417,7 +417,7 @@
   float current_device_scale_factor_;
 
   // The orientation of the display the renderer is currently on.
-  gfx::Display::Rotation current_display_rotation_;
+  display::Display::Rotation current_display_rotation_;
 
   // Whether pinch-to-zoom should be enabled and pinch events forwarded to the
   // renderer.
diff --git a/content/browser/renderer_host/render_widget_host_view_base_unittest.cc b/content/browser/renderer_host/render_widget_host_view_base_unittest.cc
index 8277d1f6..acce950 100644
--- a/content/browser/renderer_host/render_widget_host_view_base_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_base_unittest.cc
@@ -6,14 +6,14 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationType.h"
-#include "ui/gfx/display.h"
+#include "ui/display/display.h"
 
 namespace content {
 
 namespace {
 
-gfx::Display CreateDisplay(int width, int height, int angle) {
-  gfx::Display display;
+display::Display CreateDisplay(int width, int height, int angle) {
+  display::Display display;
   display.SetRotationAsDegree(angle);
   display.set_bounds(gfx::Rect(width, height));
 
@@ -25,7 +25,7 @@
 TEST(RenderWidgetHostViewBaseTest, OrientationTypeForMobile) {
   // Square display (width == height).
   {
-    gfx::Display display = CreateDisplay(100, 100, 0);
+    display::Display display = CreateDisplay(100, 100, 0);
     EXPECT_EQ(blink::WebScreenOrientationPortraitPrimary,
               RenderWidgetHostViewBase::GetOrientationTypeForMobile(display));
 
@@ -44,7 +44,7 @@
 
   // natural width > natural height.
   {
-    gfx::Display display = CreateDisplay(1, 0, 0);
+    display::Display display = CreateDisplay(1, 0, 0);
     EXPECT_EQ(blink::WebScreenOrientationLandscapePrimary,
               RenderWidgetHostViewBase::GetOrientationTypeForMobile(display));
 
@@ -63,7 +63,7 @@
 
   // natural width < natural height.
   {
-    gfx::Display display = CreateDisplay(0, 1, 0);
+    display::Display display = CreateDisplay(0, 1, 0);
     EXPECT_EQ(blink::WebScreenOrientationPortraitPrimary,
               RenderWidgetHostViewBase::GetOrientationTypeForMobile(display));
 
@@ -90,7 +90,7 @@
 
   // natural width > natural height.
   {
-    gfx::Display display = CreateDisplay(1, 0, 0);
+    display::Display display = CreateDisplay(1, 0, 0);
     blink::WebScreenOrientationType landscape_1 =
         RenderWidgetHostViewBase::GetOrientationTypeForDesktop(display);
     EXPECT_TRUE(landscape_1 == blink::WebScreenOrientationLandscapePrimary ||
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.h b/content/browser/renderer_host/render_widget_host_view_mac.h
index add3fbe..fd4e494 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.h
+++ b/content/browser/renderer_host/render_widget_host_view_mac.h
@@ -38,7 +38,7 @@
 #import "ui/base/cocoa/command_dispatcher.h"
 #include "ui/base/cocoa/remote_layer_api.h"
 #import "ui/base/cocoa/tool_tip_base_view.h"
-#include "ui/gfx/display_observer.h"
+#include "ui/display/display_observer.h"
 
 namespace content {
 class RenderWidgetHostImpl;
@@ -229,7 +229,7 @@
       public DelegatedFrameHostClient,
       public ui::AcceleratedWidgetMacNSView,
       public IPC::Sender,
-      public gfx::DisplayObserver,
+      public display::DisplayObserver,
       public cc::BeginFrameObserverBase {
  public:
   // The view will associate itself with the given widget. The native view must
@@ -355,10 +355,10 @@
   // IPC::Sender implementation.
   bool Send(IPC::Message* message) override;
 
-  // gfx::DisplayObserver implementation.
-  void OnDisplayAdded(const gfx::Display& new_display) override;
-  void OnDisplayRemoved(const gfx::Display& old_display) override;
-  void OnDisplayMetricsChanged(const gfx::Display& display,
+  // display::DisplayObserver implementation.
+  void OnDisplayAdded(const display::Display& new_display) override;
+  void OnDisplayRemoved(const display::Display& old_display) override;
+  void OnDisplayMetricsChanged(const display::Display& display,
                                uint32_t metrics) override;
 
   // Forwards the mouse event to the renderer.
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index d593431..c37835e 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -124,8 +124,6 @@
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/accessibility/ax_tree_combiner.h"
 #include "ui/base/layout.h"
-#include "ui/gfx/display.h"
-#include "ui/gfx/screen.h"
 #include "ui/gl/gl_switches.h"
 
 #if defined(OS_ANDROID)
diff --git a/content/browser/web_contents/web_contents_view_aura.cc b/content/browser/web_contents/web_contents_view_aura.cc
index c710eaf6..2df2944 100644
--- a/content/browser/web_contents/web_contents_view_aura.cc
+++ b/content/browser/web_contents/web_contents_view_aura.cc
@@ -62,13 +62,13 @@
 #include "ui/base/dragdrop/os_exchange_data.h"
 #include "ui/base/hit_test.h"
 #include "ui/compositor/layer.h"
+#include "ui/display/screen.h"
 #include "ui/events/event.h"
 #include "ui/events/event_utils.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/image/image_png_rep.h"
 #include "ui/gfx/image/image_skia.h"
-#include "ui/gfx/screen.h"
 #include "ui/touch_selection/touch_selection_controller.h"
 #include "ui/wm/public/drag_drop_client.h"
 #include "ui/wm/public/drag_drop_delegate.h"
@@ -538,7 +538,7 @@
     return;
 
   aura::Window* window = GetContentNativeView();
-  gfx::Point screen_loc = gfx::Screen::GetScreen()->GetCursorScreenPoint();
+  gfx::Point screen_loc = display::Screen::GetScreen()->GetCursorScreenPoint();
   gfx::Point client_loc = screen_loc;
   aura::client::ScreenPositionClient* screen_position_client =
       aura::client::GetScreenPositionClient(window->GetRootWindow());
@@ -1046,7 +1046,7 @@
       web_contents_->GetDelegate()->ActivateContents(web_contents_);
 
   web_contents_->GetDelegate()->ContentsMouseEvent(
-      web_contents_, gfx::Screen::GetScreen()->GetCursorScreenPoint(),
+      web_contents_, display::Screen::GetScreen()->GetCursorScreenPoint(),
       type == ui::ET_MOUSE_MOVED, type == ui::ET_MOUSE_EXITED);
 }
 
@@ -1071,7 +1071,7 @@
   if (drag_dest_delegate_)
     drag_dest_delegate_->DragInitialize(web_contents_);
 
-  gfx::Point screen_pt = gfx::Screen::GetScreen()->GetCursorScreenPoint();
+  gfx::Point screen_pt = display::Screen::GetScreen()->GetCursorScreenPoint();
   web_contents_->GetRenderViewHost()->DragTargetDragEnter(
       *current_drop_data_.get(), event.location(), screen_pt, op,
       ConvertAuraEventFlagsToWebInputEventModifiers(event.flags()));
@@ -1091,7 +1091,7 @@
     return ui::DragDropTypes::DRAG_NONE;
 
   blink::WebDragOperationsMask op = ConvertToWeb(event.source_operations());
-  gfx::Point screen_pt = gfx::Screen::GetScreen()->GetCursorScreenPoint();
+  gfx::Point screen_pt = display::Screen::GetScreen()->GetCursorScreenPoint();
   web_contents_->GetRenderViewHost()->DragTargetDragOver(
       event.location(), screen_pt, op,
       ConvertAuraEventFlagsToWebInputEventModifiers(event.flags()));
@@ -1126,7 +1126,7 @@
     return ui::DragDropTypes::DRAG_NONE;
 
   web_contents_->GetRenderViewHost()->DragTargetDrop(
-      event.location(), gfx::Screen::GetScreen()->GetCursorScreenPoint(),
+      event.location(), display::Screen::GetScreen()->GetCursorScreenPoint(),
       ConvertAuraEventFlagsToWebInputEventModifiers(event.flags()));
   if (drag_dest_delegate_)
     drag_dest_delegate_->OnDrop();
diff --git a/content/common/cursors/webcursor.h b/content/common/cursors/webcursor.h
index c306baf..9bbdd1e 100644
--- a/content/common/cursors/webcursor.h
+++ b/content/common/cursors/webcursor.h
@@ -11,7 +11,7 @@
 #include "build/build_config.h"
 #include "content/common/content_export.h"
 #include "third_party/WebKit/public/platform/WebCursorInfo.h"
-#include "ui/gfx/display.h"
+#include "ui/display/display.h"
 #include "ui/gfx/geometry/point.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/native_widget_types.h"
@@ -109,7 +109,7 @@
   ui::PlatformCursor GetPlatformCursor();
 
   // Updates |device_scale_factor_| and |rotation_| based on |display|.
-  void SetDisplayInfo(const gfx::Display& display);
+  void SetDisplayInfo(const display::Display& display);
 
   float GetCursorScaleFactor();
 
@@ -197,7 +197,7 @@
 #endif
 
 #if defined(USE_OZONE)
-  gfx::Display::Rotation rotation_;
+  display::Display::Rotation rotation_;
   gfx::Size maximum_cursor_size_;
 #endif
 };
diff --git a/content/common/cursors/webcursor_android.cc b/content/common/cursors/webcursor_android.cc
index a932b27..d1d720e 100644
--- a/content/common/cursors/webcursor_android.cc
+++ b/content/common/cursors/webcursor_android.cc
@@ -17,7 +17,7 @@
 // In the future when we want to support cursors of various kinds in Aura on
 // Android, we should switch to using webcursor_aura rather than add an
 // implementation here.
-void WebCursor::SetDisplayInfo(const gfx::Display& display) {
+void WebCursor::SetDisplayInfo(const display::Display& display) {
 }
 #endif
 
diff --git a/content/common/cursors/webcursor_aura.cc b/content/common/cursors/webcursor_aura.cc
index 7cd04b1..6aad277c 100644
--- a/content/common/cursors/webcursor_aura.cc
+++ b/content/common/cursors/webcursor_aura.cc
@@ -125,12 +125,12 @@
   ImageFromCustomData(bitmap);
   *hotspot = hotspot_;
   ui::ScaleAndRotateCursorBitmapAndHotpoint(
-      GetCursorScaleFactor(), gfx::Display::ROTATE_0, bitmap, hotspot);
+      GetCursorScaleFactor(), display::Display::ROTATE_0, bitmap, hotspot);
 }
 
 // ozone has its own SetDisplayInfo that takes rotation into account
 #if !defined(USE_OZONE)
-void WebCursor::SetDisplayInfo(const gfx::Display& display) {
+void WebCursor::SetDisplayInfo(const display::Display& display) {
   if (device_scale_factor_ == display.device_scale_factor())
     return;
 
diff --git a/content/common/cursors/webcursor_ozone.cc b/content/common/cursors/webcursor_ozone.cc
index e668460..6095da9f 100644
--- a/content/common/cursors/webcursor_ozone.cc
+++ b/content/common/cursors/webcursor_ozone.cc
@@ -40,7 +40,7 @@
   return platform_cursor_;
 }
 
-void WebCursor::SetDisplayInfo(const gfx::Display& display) {
+void WebCursor::SetDisplayInfo(const display::Display& display) {
   if (rotation_ == display.rotation() &&
       device_scale_factor_ == display.device_scale_factor() &&
       maximum_cursor_size_ == display.maximum_cursor_size())
@@ -64,7 +64,7 @@
 void WebCursor::InitPlatformData() {
   platform_cursor_ = NULL;
   device_scale_factor_ = 1.f;
-  rotation_ = gfx::Display::ROTATE_0;
+  rotation_ = display::Display::ROTATE_0;
   maximum_cursor_size_ =
       gfx::Size(kDefaultMaxCursorWidth, kDefaultMaxCursorHeight);
 }
diff --git a/content/common/cursors/webcursor_unittest.cc b/content/common/cursors/webcursor_unittest.cc
index dc9bdd6..37a20004 100644
--- a/content/common/cursors/webcursor_unittest.cc
+++ b/content/common/cursors/webcursor_unittest.cc
@@ -267,7 +267,7 @@
 
 #if defined(USE_AURA)
 TEST(WebCursorTest, CursorScaleFactor) {
-  gfx::Display display;
+  display::Display display;
   display.set_device_scale_factor(80.2f);
 
   WebCursor::CursorInfo info;
@@ -309,7 +309,7 @@
 
 #if defined(OS_WIN)
 void ScaleCursor(float scaleFactor, int hotspotX, int hotspotY) {
-  gfx::Display display;
+  display::Display display;
   display.set_device_scale_factor(scaleFactor);
 
   WebCursor::CursorInfo info;
diff --git a/content/common/page_state_serialization.cc b/content/common/page_state_serialization.cc
index b9670c2f2..7bbced3b 100644
--- a/content/common/page_state_serialization.cc
+++ b/content/common/page_state_serialization.cc
@@ -14,7 +14,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
-#include "ui/gfx/screen.h"
+#include "ui/display/screen.h"
 
 namespace content {
 namespace {
@@ -605,8 +605,9 @@
     if (state->page_scale_factor) {
       float device_scale_factor = g_device_scale_factor_for_testing;
       if (!device_scale_factor) {
-        device_scale_factor =
-            gfx::Screen::GetScreen()->GetPrimaryDisplay().device_scale_factor();
+        device_scale_factor = display::Screen::GetScreen()
+                                  ->GetPrimaryDisplay()
+                                  .device_scale_factor();
       }
       state->scroll_offset =
           gfx::Point(state->scroll_offset.x() / state->page_scale_factor,
diff --git a/content/public/android/java/src/org/chromium/content/app/ChildProcessService.java b/content/public/android/java/src/org/chromium/content/app/ChildProcessService.java
index 54dc6e62f..77f70e9f 100644
--- a/content/public/android/java/src/org/chromium/content/app/ChildProcessService.java
+++ b/content/public/android/java/src/org/chromium/content/app/ChildProcessService.java
@@ -116,6 +116,8 @@
         sContext.set(this);
         super.onCreate();
 
+        ContextUtils.initApplicationContext(getApplicationContext());
+
         mMainThread = new Thread(new Runnable() {
             @Override
             @SuppressFBWarnings("DM_EXIT")
@@ -187,7 +189,6 @@
                             mMainThread.wait();
                         }
                     }
-                    ContextUtils.initApplicationContext(sContext.get().getApplicationContext());
                     for (FileDescriptorInfo fdInfo : mFdInfos) {
                         nativeRegisterGlobalFileDescriptor(
                                 fdInfo.mId, fdInfo.mFd.detachFd(), fdInfo.mOffset, fdInfo.mSize);
diff --git a/content/public/android/java/src/org/chromium/content/browser/BrowserStartupController.java b/content/public/android/java/src/org/chromium/content/browser/BrowserStartupController.java
index 6c97f4c..d53701d 100644
--- a/content/public/android/java/src/org/chromium/content/browser/BrowserStartupController.java
+++ b/content/public/android/java/src/org/chromium/content/browser/BrowserStartupController.java
@@ -7,7 +7,6 @@
 import android.content.Context;
 import android.os.Handler;
 
-import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
 import org.chromium.base.ResourceExtractor;
 import org.chromium.base.ThreadUtils;
@@ -292,7 +291,6 @@
                     // TODO(yfriedman): Remove dependency on a command line flag for this.
                     DeviceUtils.addDeviceSpecificUserAgentSwitch(mContext);
 
-                    ContextUtils.initApplicationContext(mContext);
                     nativeSetCommandLineFlags(
                             singleProcess, nativeIsPluginEnabled() ? getPlugins() : null);
                     mPostResourceExtractionTasksCompleted = true;
@@ -319,8 +317,6 @@
         ResourceExtractor resourceExtractor = ResourceExtractor.get(mContext);
         resourceExtractor.startExtractingResources();
         resourceExtractor.waitForCompletion();
-
-        ContextUtils.initApplicationContext(mContext.getApplicationContext());
         nativeSetCommandLineFlags(false, null);
     }
 
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java
index 9f439139..77016cd 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java
@@ -247,6 +247,6 @@
     protected void setUp() throws Exception {
         super.setUp();
         LibraryLoader.get(LibraryProcessType.PROCESS_CHILD)
-                .ensureInitialized(getInstrumentation().getContext());
+                .ensureInitialized(getInstrumentation().getTargetContext());
     }
 }
diff --git a/content/renderer/media/user_media_client_impl.cc b/content/renderer/media/user_media_client_impl.cc
index 6b7d219..a19028a 100644
--- a/content/renderer/media/user_media_client_impl.cc
+++ b/content/renderer/media/user_media_client_impl.cc
@@ -740,16 +740,13 @@
 
   if (request_id == request->audio_input_request_id) {
     request->has_audio_input_returned = true;
-    DCHECK(request->audio_input_devices.empty());
     request->audio_input_devices = device_array;
   } else if (request_id == request->video_input_request_id) {
     request->has_video_input_returned = true;
-    DCHECK(request->video_input_devices.empty());
     request->video_input_devices = device_array;
   } else {
     DCHECK_EQ(request->audio_output_request_id, request_id);
     request->has_audio_output_returned = true;
-    DCHECK(request->audio_output_devices.empty());
     request->audio_output_devices = device_array;
   }
 
diff --git a/content/shell/browser/layout_test/blink_test_controller.cc b/content/shell/browser/layout_test/blink_test_controller.cc
index 91f7c13..450bbdf 100644
--- a/content/shell/browser/layout_test/blink_test_controller.cc
+++ b/content/shell/browser/layout_test/blink_test_controller.cc
@@ -381,10 +381,10 @@
 }
 
 void BlinkTestController::OnTestFinishedInSecondaryRenderer() {
-  RenderViewHost* render_view_host =
+  RenderViewHost* main_render_view_host =
       main_window_->web_contents()->GetRenderViewHost();
-  render_view_host->Send(
-      new ShellViewMsg_NotifyDone(render_view_host->GetRoutingID()));
+  main_render_view_host->Send(new ShellViewMsg_TestFinishedInSecondaryRenderer(
+      main_render_view_host->GetRoutingID()));
 }
 
 bool BlinkTestController::IsMainWindow(WebContents* web_contents) const {
diff --git a/content/shell/browser/layout_test/layout_test_message_filter.cc b/content/shell/browser/layout_test/layout_test_message_filter.cc
index 082fc238..c5fb851 100644
--- a/content/shell/browser/layout_test/layout_test_message_filter.cc
+++ b/content/shell/browser/layout_test/layout_test_message_filter.cc
@@ -56,6 +56,7 @@
     case LayoutTestHostMsg_SetPermission::ID:
     case LayoutTestHostMsg_ResetPermissions::ID:
     case LayoutTestHostMsg_LayoutTestRuntimeFlagsChanged::ID:
+    case LayoutTestHostMsg_TestFinishedInSecondaryRenderer::ID:
       *thread = BrowserThread::UI;
       break;
   }
@@ -80,6 +81,8 @@
     IPC_MESSAGE_HANDLER(LayoutTestHostMsg_ResetPermissions, OnResetPermissions)
     IPC_MESSAGE_HANDLER(LayoutTestHostMsg_LayoutTestRuntimeFlagsChanged,
                         OnLayoutTestRuntimeFlagsChanged)
+    IPC_MESSAGE_HANDLER(LayoutTestHostMsg_TestFinishedInSecondaryRenderer,
+                        OnTestFinishedInSecondaryRenderer)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
 
@@ -193,4 +196,8 @@
       render_process_id_, changed_layout_test_runtime_flags);
 }
 
+void LayoutTestMessageFilter::OnTestFinishedInSecondaryRenderer() {
+  BlinkTestController::Get()->OnTestFinishedInSecondaryRenderer();
+}
+
 }  // namespace content
diff --git a/content/shell/browser/layout_test/layout_test_message_filter.h b/content/shell/browser/layout_test/layout_test_message_filter.h
index 2123acfe..afab2fb 100644
--- a/content/shell/browser/layout_test/layout_test_message_filter.h
+++ b/content/shell/browser/layout_test/layout_test_message_filter.h
@@ -72,6 +72,7 @@
   void OnResetPermissions();
   void OnLayoutTestRuntimeFlagsChanged(
       const base::DictionaryValue& changed_layout_test_runtime_flags);
+  void OnTestFinishedInSecondaryRenderer();
 
   int render_process_id_;
 
diff --git a/content/shell/browser/layout_test/secondary_test_window_observer.cc b/content/shell/browser/layout_test/secondary_test_window_observer.cc
index 933ce0e..3c8794ad 100644
--- a/content/shell/browser/layout_test/secondary_test_window_observer.cc
+++ b/content/shell/browser/layout_test/secondary_test_window_observer.cc
@@ -17,21 +17,6 @@
 
 SecondaryTestWindowObserver::~SecondaryTestWindowObserver() {}
 
-bool SecondaryTestWindowObserver::OnMessageReceived(
-    const IPC::Message& message) {
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(SecondaryTestWindowObserver, message)
-    IPC_MESSAGE_HANDLER(ShellViewHostMsg_TestFinishedInSecondaryRenderer,
-                        OnTestFinishedInSecondaryRenderer)
-    IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-  return handled;
-}
-
-void SecondaryTestWindowObserver::OnTestFinishedInSecondaryRenderer() {
-  BlinkTestController::Get()->OnTestFinishedInSecondaryRenderer();
-}
-
 void SecondaryTestWindowObserver::RenderFrameCreated(
     RenderFrameHost* render_frame_host) {
   DCHECK(!BlinkTestController::Get()->IsMainWindow(
diff --git a/content/shell/browser/layout_test/secondary_test_window_observer.h b/content/shell/browser/layout_test/secondary_test_window_observer.h
index b41a95b..5e7f758 100644
--- a/content/shell/browser/layout_test/secondary_test_window_observer.h
+++ b/content/shell/browser/layout_test/secondary_test_window_observer.h
@@ -18,18 +18,14 @@
   ~SecondaryTestWindowObserver() override;
 
   // WebContentsObserver implementation.
-  bool OnMessageReceived(const IPC::Message& message) override;
   void RenderFrameCreated(RenderFrameHost* render_frame_host) override;
   void RenderFrameHostChanged(RenderFrameHost* old_host,
                               RenderFrameHost* new_host) override;
 
  private:
   friend class WebContentsUserData<SecondaryTestWindowObserver>;
-
   explicit SecondaryTestWindowObserver(WebContents* web_contents);
 
-  void OnTestFinishedInSecondaryRenderer();
-
   DISALLOW_COPY_AND_ASSIGN(SecondaryTestWindowObserver);
 };
 
diff --git a/content/shell/browser/shell.h b/content/shell/browser/shell.h
index 547f338..590ccfd 100644
--- a/content/shell/browser/shell.h
+++ b/content/shell/browser/shell.h
@@ -25,6 +25,10 @@
 namespace gfx {
 class Screen;
 }
+namespace display {
+using Screen = gfx::Screen;
+}
+
 namespace wm {
 class WMTestHelper;
 }
@@ -249,7 +253,7 @@
 #elif defined(USE_AURA)
 #if defined(OS_CHROMEOS)
   static wm::WMTestHelper* wm_test_helper_;
-  static gfx::Screen* test_screen_;
+  static display::Screen* test_screen_;
 #endif
 #if defined(TOOLKIT_VIEWS)
   static views::ViewsDelegate* views_delegate_;
diff --git a/content/shell/browser/shell_aura.cc b/content/shell/browser/shell_aura.cc
index cf704b93..dff4c2a 100644
--- a/content/shell/browser/shell_aura.cc
+++ b/content/shell/browser/shell_aura.cc
@@ -17,7 +17,7 @@
 void Shell::PlatformInitialize(const gfx::Size& default_window_size) {
   CHECK(!platform_);
   aura::TestScreen* screen = aura::TestScreen::Create(gfx::Size());
-  gfx::Screen::SetScreenInstance(screen);
+  display::Screen::SetScreenInstance(screen);
   platform_ = new ShellPlatformDataAura(default_window_size);
 }
 
diff --git a/content/shell/browser/shell_platform_data_aura.cc b/content/shell/browser/shell_platform_data_aura.cc
index 293b566..af14bb7 100644
--- a/content/shell/browser/shell_platform_data_aura.cc
+++ b/content/shell/browser/shell_platform_data_aura.cc
@@ -16,7 +16,6 @@
 #include "ui/base/ime/input_method.h"
 #include "ui/base/ime/input_method_delegate.h"
 #include "ui/base/ime/input_method_factory.h"
-#include "ui/gfx/screen.h"
 #include "ui/wm/core/default_activation_client.h"
 
 namespace content {
diff --git a/content/shell/browser/shell_views.cc b/content/shell/browser/shell_views.cc
index f7f8f286..1ca8493 100644
--- a/content/shell/browser/shell_views.cc
+++ b/content/shell/browser/shell_views.cc
@@ -22,8 +22,8 @@
 #include "ui/base/clipboard/clipboard.h"
 #include "ui/base/models/simple_menu_model.h"
 #include "ui/base/resource/resource_bundle.h"
+#include "ui/display/screen.h"
 #include "ui/events/event.h"
-#include "ui/gfx/screen.h"
 #include "ui/views/background.h"
 #include "ui/views/controls/button/label_button.h"
 #include "ui/views/controls/button/menu_button.h"
@@ -385,7 +385,7 @@
 
 #if defined(OS_CHROMEOS)
 wm::WMTestHelper* Shell::wm_test_helper_ = NULL;
-gfx::Screen* Shell::test_screen_ = NULL;
+display::Screen* Shell::test_screen_ = NULL;
 #endif
 views::ViewsDelegate* Shell::views_delegate_ = NULL;
 
@@ -397,11 +397,11 @@
 #endif
 #if defined(OS_CHROMEOS)
   test_screen_ = aura::TestScreen::Create(gfx::Size());
-  gfx::Screen::SetScreenInstance(test_screen_);
+  display::Screen::SetScreenInstance(test_screen_);
   wm_test_helper_ = new wm::WMTestHelper(default_window_size,
                                          GetContextFactory());
 #else
-  gfx::Screen::SetScreenInstance(views::CreateDesktopScreen());
+  display::Screen::SetScreenInstance(views::CreateDesktopScreen());
 #endif
   views_delegate_ = new views::DesktopTestViewsDelegate();
 }
diff --git a/content/shell/common/layout_test/layout_test_messages.h b/content/shell/common/layout_test/layout_test_messages.h
index b9712e5..2946722b8 100644
--- a/content/shell/common/layout_test/layout_test_messages.h
+++ b/content/shell/common/layout_test/layout_test_messages.h
@@ -52,3 +52,6 @@
 IPC_MESSAGE_CONTROL1(
     LayoutTestMsg_ReplicateLayoutTestRuntimeFlagsChanges,
     base::DictionaryValue /* changed_layout_test_runtime_flags */)
+
+// Sent by secondary test window to notify the test has finished.
+IPC_MESSAGE_CONTROL0(LayoutTestHostMsg_TestFinishedInSecondaryRenderer)
diff --git a/content/shell/common/shell_messages.h b/content/shell/common/shell_messages.h
index 248ca20..ef45330 100644
--- a/content/shell/common/shell_messages.h
+++ b/content/shell/common/shell_messages.h
@@ -50,9 +50,9 @@
 // main test window) for a layout test.
 IPC_MESSAGE_ROUTED0(ShellViewMsg_SetupSecondaryRenderer)
 
-// Tells the main window that a secondary renderer in a different process thinks
-// the test is finished.
-IPC_MESSAGE_ROUTED0(ShellViewMsg_NotifyDone)
+// Tells the main window that a secondary renderer in a different process asked
+// to finish the test.
+IPC_MESSAGE_ROUTED0(ShellViewMsg_TestFinishedInSecondaryRenderer)
 
 // Pushes a snapshot of the current session history from the browser process.
 // This includes only information about those RenderViews that are in the
@@ -100,8 +100,6 @@
 
 IPC_MESSAGE_ROUTED0(ShellViewHostMsg_ResetDone)
 
-IPC_MESSAGE_ROUTED0(ShellViewHostMsg_TestFinishedInSecondaryRenderer)
-
 // WebTestDelegate related.
 IPC_MESSAGE_ROUTED1(ShellViewHostMsg_OverridePreferences,
                     content::WebPreferences /* preferences */)
diff --git a/content/shell/renderer/layout_test/blink_test_runner.cc b/content/shell/renderer/layout_test/blink_test_runner.cc
index e90df06..81a61a31 100644
--- a/content/shell/renderer/layout_test/blink_test_runner.cc
+++ b/content/shell/renderer/layout_test/blink_test_runner.cc
@@ -534,7 +534,8 @@
 
 void BlinkTestRunner::TestFinished() {
   if (!is_main_window_ || !render_view()->GetMainRenderFrame()) {
-    Send(new ShellViewHostMsg_TestFinishedInSecondaryRenderer(routing_id()));
+    RenderThread::Get()->Send(
+        new LayoutTestHostMsg_TestFinishedInSecondaryRenderer());
     return;
   }
   test_runner::WebTestInterfaces* interfaces =
@@ -716,7 +717,8 @@
   IPC_BEGIN_MESSAGE_MAP(BlinkTestRunner, message)
     IPC_MESSAGE_HANDLER(ShellViewMsg_SessionHistory, OnSessionHistory)
     IPC_MESSAGE_HANDLER(ShellViewMsg_Reset, OnReset)
-    IPC_MESSAGE_HANDLER(ShellViewMsg_NotifyDone, OnNotifyDone)
+    IPC_MESSAGE_HANDLER(ShellViewMsg_TestFinishedInSecondaryRenderer,
+                        OnTestFinishedInSecondaryRenderer)
     IPC_MESSAGE_HANDLER(ShellViewMsg_TryLeakDetection, OnTryLeakDetection)
     IPC_MESSAGE_HANDLER(ShellViewMsg_ReplyBluetoothManualChooserEvents,
                         OnReplyBluetoothManualChooserEvents)
@@ -938,9 +940,9 @@
   Send(new ShellViewHostMsg_ResetDone(routing_id()));
 }
 
-void BlinkTestRunner::OnNotifyDone() {
-  render_view()->GetWebView()->mainFrame()->executeScript(
-      WebScriptSource(WebString::fromUTF8("testRunner.notifyDone();")));
+void BlinkTestRunner::OnTestFinishedInSecondaryRenderer() {
+  DCHECK(is_main_window_ && render_view()->GetMainRenderFrame());
+  TestFinished();
 }
 
 void BlinkTestRunner::OnTryLeakDetection() {
diff --git a/content/shell/renderer/layout_test/blink_test_runner.h b/content/shell/renderer/layout_test/blink_test_runner.h
index c5329e0..91d527a9 100644
--- a/content/shell/renderer/layout_test/blink_test_runner.h
+++ b/content/shell/renderer/layout_test/blink_test_runner.h
@@ -176,7 +176,7 @@
       const std::vector<std::vector<PageState> >& session_histories,
       const std::vector<unsigned>& current_entry_indexes);
   void OnReset();
-  void OnNotifyDone();
+  void OnTestFinishedInSecondaryRenderer();
   void OnTryLeakDetection();
   void OnReplyBluetoothManualChooserEvents(
       const std::vector<std::string>& events);
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index b2dde28..cd17f0a 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -687,6 +687,7 @@
     "//ui/accessibility",
     "//ui/base:test_support",
     "//ui/compositor:test_support",
+    "//ui/display",
     "//ui/events/blink",
     "//ui/gfx:test_support",
     "//ui/gfx/geometry",
diff --git a/extensions/renderer/api/display_source/display_source_session.cc b/extensions/renderer/api/display_source/display_source_session.cc
index 8759977..ae2b6754 100644
--- a/extensions/renderer/api/display_source/display_source_session.cc
+++ b/extensions/renderer/api/display_source/display_source_session.cc
@@ -40,8 +40,9 @@
     const DisplaySourceSessionParams& params) {
 #if defined(ENABLE_WIFI_DISPLAY)
   return std::unique_ptr<DisplaySourceSession>(new WiFiDisplaySession(params));
-#endif
+#else
   return nullptr;
+#endif
 }
 
 }  // namespace extensions
diff --git a/extensions/renderer/api/display_source/wifi_display/wifi_display_media_packetizer_unittest.cc b/extensions/renderer/api/display_source/wifi_display/wifi_display_media_packetizer_unittest.cc
index 8a5839b..eae5c27 100644
--- a/extensions/renderer/api/display_source/wifi_display/wifi_display_media_packetizer_unittest.cc
+++ b/extensions/renderer/api/display_source/wifi_display/wifi_display_media_packetizer_unittest.cc
@@ -169,7 +169,8 @@
 };
 
 struct ProgramClockReference {
-  enum { kInvalidBase = ~static_cast<uint64_t>(0u) };
+  static const uint64_t kInvalidBase = ~static_cast<uint64_t>(0u);
+
   uint64_t base;
   uint16_t extension;
 };
@@ -560,14 +561,13 @@
           ? WiFiDisplayElementaryStreamPacketizer::kFirstVideoStreamId
           : WiFiDisplayElementaryStreamPacketizer::kFirstAudioStreamId;
 
-  WiFiDisplayElementaryStreamPacketizer packetizer;
   uint8_t unit_header_data[kMaxUnitHeaderSize];
   for (size_t unit_header_size = 0u; unit_header_size <= kMaxUnitHeaderSize;
        ++unit_header_size) {
     WiFiDisplayElementaryStreamPacket packet =
-        packetizer.EncodeElementaryStreamUnit(stream_id, unit_header_data,
-                                              unit_header_size, unit_.data(),
-                                              unit_.size(), pts_, dts_);
+        WiFiDisplayElementaryStreamPacketizer::EncodeElementaryStreamUnit(
+            stream_id, unit_header_data, unit_header_size, unit_.data(),
+            unit_.size(), pts_, dts_);
     CheckElementaryStreamPacketHeader(packet, stream_id);
     CheckElementaryStreamPacketUnitHeader(packet, unit_header_data,
                                           unit_header_size);
@@ -672,7 +672,6 @@
   stream_infos.emplace_back(WiFiDisplayElementaryStreamInfo::AUDIO_LPCM,
                             std::move(lpcm_descriptors));
   stream_infos.emplace_back(WiFiDisplayElementaryStreamInfo::AUDIO_AAC);
-  WiFiDisplayElementaryStreamPacketizer elementary_stream_packetizer;
   FakeTransportStreamPacketizer packetizer(
       base::TimeDelta::FromMilliseconds(200), stream_infos);
 
@@ -696,7 +695,7 @@
       auto normalized_dts = dts_;
       packetizer.NormalizeUnitTimeStamps(&normalized_pts, &normalized_dts);
       WiFiDisplayElementaryStreamPacket elementary_stream_packet =
-          elementary_stream_packetizer.EncodeElementaryStreamUnit(
+          WiFiDisplayElementaryStreamPacketizer::EncodeElementaryStreamUnit(
               kStreamIds[stream_index], unit_header_data, unit_header_size,
               unit_.data(), unit_.size(), normalized_pts, normalized_dts);
 
@@ -783,7 +782,7 @@
 
   // Check datagram packets.
   ProgramClockReference pcr = {ProgramClockReference::kInvalidBase, 0u};
-  uint16_t sequence_number;
+  uint16_t sequence_number = 0u;
   uint32_t synchronization_source_identifier;
   auto transport_stream_packet_it = transport_stream_packets.cbegin();
   for (const auto& packet : packets) {
diff --git a/extensions/renderer/api/display_source/wifi_display/wifi_display_transport_stream_packetizer.cc b/extensions/renderer/api/display_source/wifi_display/wifi_display_transport_stream_packetizer.cc
index 6c1917e..22e1bcf 100644
--- a/extensions/renderer/api/display_source/wifi_display/wifi_display_transport_stream_packetizer.cc
+++ b/extensions/renderer/api/display_source/wifi_display/wifi_display_transport_stream_packetizer.cc
@@ -460,9 +460,8 @@
   UpdateDelayForUnitTimeStamps(pts, dts);
   NormalizeUnitTimeStamps(&pts, &dts);
 
-  WiFiDisplayElementaryStreamPacketizer elementary_stream_packetizer;
   WiFiDisplayElementaryStreamPacket elementary_stream_packet =
-      elementary_stream_packetizer.EncodeElementaryStreamUnit(
+      WiFiDisplayElementaryStreamPacketizer::EncodeElementaryStreamUnit(
           stream_state.stream_id, stream_state.unit_header.data,
           stream_state.unit_header.size, unit_data, unit_size, pts, dts);
 
@@ -477,14 +476,10 @@
     //    (only for the first and/or the last packet):
     //     - for the first packet to hold flags
     //     - for the last packet to hold padding
-    //  * PES packet header (only for the first packet):
-    //     - PES packet header base
-    //     - Optional PES header base
-    //     - Optional PES header optional fields:
-    //        - Presentation time stamp
-    //        - Decoding time stamp
+    //  * Elementary stream packet header (only for the first packet)
+    //  * Elementary stream packet unit header (only for the first packet)
     bool adaptation_field_flag = false;
-    size_t header_min_size;
+    size_t header_min_size = 0u;
     const bool is_payload_unit_start_or_end =
         is_payload_unit_start ||
         remaining_unit_size <= WiFiDisplayTransportStreamPacket::kPacketSize -
diff --git a/gpu/ipc/common/gpu_param_traits_macros.h b/gpu/ipc/common/gpu_param_traits_macros.h
index d610357..8c65904 100644
--- a/gpu/ipc/common/gpu_param_traits_macros.h
+++ b/gpu/ipc/common/gpu_param_traits_macros.h
@@ -11,7 +11,6 @@
 #include "gpu/gpu_export.h"
 #include "gpu/ipc/common/gpu_stream_constants.h"
 #include "ipc/ipc_message_macros.h"
-#include "ui/gfx/gpu_memory_buffer.h"
 #include "ui/gfx/ipc/geometry/gfx_param_traits.h"
 #include "ui/gfx/ipc/gfx_param_traits.h"
 #include "ui/gfx/swap_result.h"
@@ -40,26 +39,6 @@
   IPC_STRUCT_TRAITS_MEMBER(max_framerate_denominator)
 IPC_STRUCT_TRAITS_END()
 
-IPC_ENUM_TRAITS_MAX_VALUE(gfx::GpuMemoryBufferType,
-                          gfx::GPU_MEMORY_BUFFER_TYPE_LAST)
-
-IPC_STRUCT_TRAITS_BEGIN(gfx::GpuMemoryBufferHandle)
-  IPC_STRUCT_TRAITS_MEMBER(id)
-  IPC_STRUCT_TRAITS_MEMBER(type)
-  IPC_STRUCT_TRAITS_MEMBER(handle)
-  IPC_STRUCT_TRAITS_MEMBER(offset)
-  IPC_STRUCT_TRAITS_MEMBER(stride)
-#if defined(USE_OZONE)
-  IPC_STRUCT_TRAITS_MEMBER(native_pixmap_handle)
-#elif defined(OS_MACOSX)
-  IPC_STRUCT_TRAITS_MEMBER(mach_port)
-#endif
-IPC_STRUCT_TRAITS_END()
-
-IPC_STRUCT_TRAITS_BEGIN(gfx::GpuMemoryBufferId)
-  IPC_STRUCT_TRAITS_MEMBER(id)
-IPC_STRUCT_TRAITS_END()
-
 IPC_ENUM_TRAITS_MAX_VALUE(gfx::GpuPreference, gfx::GpuPreferenceLast)
 IPC_ENUM_TRAITS_MAX_VALUE(gpu::GpuStreamPriority, gpu::GpuStreamPriority::LAST)
 IPC_ENUM_TRAITS_MAX_VALUE(gfx::SwapResult, gfx::SwapResult::SWAP_RESULT_LAST)
diff --git a/ios/third_party/earl_grey/earl_grey.gyp b/ios/third_party/earl_grey/earl_grey.gyp
index cdd6fcd..7cfd3cd 100644
--- a/ios/third_party/earl_grey/earl_grey.gyp
+++ b/ios/third_party/earl_grey/earl_grey.gyp
@@ -272,6 +272,11 @@
         'CODE_SIGN_IDENTITY[sdk=iphoneos*]': 'iPhone Developer',
         'BUNDLE_IDENTIFIER': 'com.google.earlgrey.EarlGrey',
         'INFOPLIST_FILE': 'src/EarlGrey-Info.plist',
+        'DYLIB_INSTALL_NAME_BASE': '@rpath',
+        'OTHER_LDFLAGS': [
+          '-Xlinker', '-rpath', '-Xlinker', '@executable_path/Frameworks',
+          '-Xlinker', '-rpath', '-Xlinker', '@loader_path/Frameworks'
+        ]
       },
       'link_settings': {
         'libraries': [
diff --git a/ios/third_party/ochamcrest/ochamcrest.gyp b/ios/third_party/ochamcrest/ochamcrest.gyp
index 9ca749b..bf1ec1b 100644
--- a/ios/third_party/ochamcrest/ochamcrest.gyp
+++ b/ios/third_party/ochamcrest/ochamcrest.gyp
@@ -230,6 +230,11 @@
         'CODE_SIGN_IDENTITY[sdk=iphoneos*]': 'iPhone Developer',
         'PRODUCT_BUNDLE_IDENTIFIER': 'org.hamcrest.OCHamcrest.OCHamcrest-iOS',
         'INFOPLIST_FILE': 'src/Source/OCHamcrest-Info.plist',
+        'DYLIB_INSTALL_NAME_BASE': '@rpath',
+        'OTHER_LDFLAGS': [
+          '-Xlinker', '-rpath', '-Xlinker', '@executable_path/Frameworks',
+          '-Xlinker', '-rpath', '-Xlinker', '@loader_path/Frameworks'
+        ]
       },
       'include_dirs': [
         'src',
diff --git a/ios/web/ios_web_shell_tests.gyp b/ios/web/ios_web_shell_tests.gyp
index 4bc2817b..685b266 100644
--- a/ios/web/ios_web_shell_tests.gyp
+++ b/ios/web/ios_web_shell_tests.gyp
@@ -51,6 +51,10 @@
       },
       'xcode_settings': {
         'INFOPLIST_FILE': 'shell/test/Host-Info.plist',
+        'OTHER_LDFLAGS': [
+          '-Xlinker', '-rpath', '-Xlinker', '@executable_path/Frameworks',
+          '-Xlinker', '-rpath', '-Xlinker', '@loader_path/Frameworks'
+        ]
       },
       'dependencies': [
         'ios_web_shell_test_support',
diff --git a/mojo/android/javatests/src/org/chromium/mojo/MojoTestCase.java b/mojo/android/javatests/src/org/chromium/mojo/MojoTestCase.java
index 3e81b7a8..c7348caa 100644
--- a/mojo/android/javatests/src/org/chromium/mojo/MojoTestCase.java
+++ b/mojo/android/javatests/src/org/chromium/mojo/MojoTestCase.java
@@ -4,6 +4,7 @@
 
 package org.chromium.mojo;
 
+import android.content.Context;
 import android.test.InstrumentationTestCase;
 
 import org.chromium.base.ContextUtils;
@@ -25,9 +26,9 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        LibraryLoader.get(LibraryProcessType.PROCESS_BROWSER)
-                .ensureInitialized(getInstrumentation().getTargetContext());
-        ContextUtils.initApplicationContext(getInstrumentation().getTargetContext());
+        Context appContext = getInstrumentation().getTargetContext().getApplicationContext();
+        ContextUtils.initApplicationContext(appContext);
+        LibraryLoader.get(LibraryProcessType.PROCESS_BROWSER).ensureInitialized(appContext);
         nativeInit();
         mTestEnvironmentPointer = nativeSetupTestEnvironment();
     }
diff --git a/mojo/edk/system/message_pipe_perftest.cc b/mojo/edk/system/message_pipe_perftest.cc
index 6e348c8..63ae6c57 100644
--- a/mojo/edk/system/message_pipe_perftest.cc
+++ b/mojo/edk/system/message_pipe_perftest.cc
@@ -5,12 +5,16 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include <memory>
 #include <utility>
 
 #include "base/bind.h"
+#include "base/bind_helpers.h"
 #include "base/logging.h"
+#include "base/macros.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/perf_time_logger.h"
+#include "base/threading/thread.h"
 #include "mojo/edk/embedder/embedder.h"
 #include "mojo/edk/embedder/scoped_platform_handle.h"
 #include "mojo/edk/system/handle_signals_state.h"
@@ -25,11 +29,9 @@
 namespace edk {
 namespace {
 
-class MultiprocessMessagePipePerfTest : public test::MojoTestBase {
+class MessagePipePerfTest : public test::MojoTestBase {
  public:
-  MultiprocessMessagePipePerfTest()
-      : message_count_(0),
-        message_size_(0) {}
+  MessagePipePerfTest() : message_count_(0), message_size_(0) {}
 
   void SetUpMeasurement(int message_count, size_t message_size) {
     message_count_ = message_count;
@@ -76,50 +78,82 @@
     logger.Done();
   }
 
+ protected:
+  void RunPingPongServer(MojoHandle mp) {
+    // This values are set to align with one at ipc_pertests.cc for comparison.
+    const size_t kMsgSize[5] = {12, 144, 1728, 20736, 248832};
+    const int kMessageCount[5] = {50000, 50000, 50000, 12000, 1000};
+
+    for (size_t i = 0; i < 5; i++) {
+      SetUpMeasurement(kMessageCount[i], kMsgSize[i]);
+      Measure(mp);
+    }
+
+    SendQuitMessage(mp);
+  }
+
+  static int RunPingPongClient(MojoHandle mp) {
+    std::string buffer(1000000, '\0');
+    int rv = 0;
+    while (true) {
+      // Wait for our end of the message pipe to be readable.
+      HandleSignalsState hss;
+      MojoResult result =
+          MojoWait(mp, MOJO_HANDLE_SIGNAL_READABLE,
+                   MOJO_DEADLINE_INDEFINITE, &hss);
+      if (result != MOJO_RESULT_OK) {
+        rv = result;
+        break;
+      }
+
+      uint32_t read_size = static_cast<uint32_t>(buffer.size());
+      CHECK_EQ(MojoReadMessage(mp, &buffer[0],
+                               &read_size, nullptr,
+                               0, MOJO_READ_MESSAGE_FLAG_NONE),
+               MOJO_RESULT_OK);
+
+      // Empty message indicates quit.
+      if (read_size == 0)
+        break;
+
+      CHECK_EQ(MojoWriteMessage(mp, &buffer[0],
+                                read_size,
+                                nullptr, 0, MOJO_WRITE_MESSAGE_FLAG_NONE),
+               MOJO_RESULT_OK);
+    }
+
+    return rv;
+  }
+
  private:
   int message_count_;
   size_t message_size_;
   std::string payload_;
   std::string read_buffer_;
   std::unique_ptr<base::PerfTimeLogger> perf_logger_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessagePipePerfTest);
 };
 
+TEST_F(MessagePipePerfTest, PingPong) {
+  MojoHandle server_handle, client_handle;
+  CreateMessagePipe(&server_handle, &client_handle);
+
+  base::Thread client_thread("PingPongClient");
+  client_thread.Start();
+  client_thread.task_runner()->PostTask(
+      FROM_HERE,
+      base::Bind(base::IgnoreResult(&RunPingPongClient), client_handle));
+
+  RunPingPongServer(server_handle);
+}
+
 // For each message received, sends a reply message with the same contents
 // repeated twice, until the other end is closed or it receives "quitquitquit"
 // (which it doesn't reply to). It'll return the number of messages received,
 // not including any "quitquitquit" message, modulo 100.
-DEFINE_TEST_CLIENT_WITH_PIPE(PingPongClient, MultiprocessMessagePipePerfTest,
-                             h) {
-  std::string buffer(1000000, '\0');
-  int rv = 0;
-  while (true) {
-    // Wait for our end of the message pipe to be readable.
-    HandleSignalsState hss;
-    MojoResult result =
-        MojoWait(h, MOJO_HANDLE_SIGNAL_READABLE,
-                 MOJO_DEADLINE_INDEFINITE, &hss);
-    if (result != MOJO_RESULT_OK) {
-      rv = result;
-      break;
-    }
-
-    uint32_t read_size = static_cast<uint32_t>(buffer.size());
-    CHECK_EQ(MojoReadMessage(h, &buffer[0],
-                             &read_size, nullptr,
-                             0, MOJO_READ_MESSAGE_FLAG_NONE),
-             MOJO_RESULT_OK);
-
-    // Empty message indicates quit.
-    if (read_size == 0)
-      break;
-
-    CHECK_EQ(MojoWriteMessage(h, &buffer[0],
-                              read_size,
-                              nullptr, 0, MOJO_WRITE_MESSAGE_FLAG_NONE),
-             MOJO_RESULT_OK);
-  }
-
-  return rv;
+DEFINE_TEST_CLIENT_WITH_PIPE(PingPongClient, MessagePipePerfTest, h) {
+  return RunPingPongClient(h);
 }
 
 // Repeatedly sends messages as previous one got replied by the child.
@@ -127,22 +161,13 @@
 // number of messages has been sent.
 #if defined(OS_ANDROID)
 // Android multi-process tests are not executing the new process. This is flaky.
-#define MAYBE_PingPong DISABLED_PingPong
+#define MAYBE_MultiprocessPingPong DISABLED_MultiprocessPingPong
 #else
-#define MAYBE_PingPong PingPong
+#define MAYBE_MultiprocessPingPong MultiprocessPingPong
 #endif  // defined(OS_ANDROID)
-TEST_F(MultiprocessMessagePipePerfTest, MAYBE_PingPong) {
+TEST_F(MessagePipePerfTest, MAYBE_MultiprocessPingPong) {
   RUN_CHILD_ON_PIPE(PingPongClient, h)
-    // This values are set to align with one at ipc_pertests.cc for comparison.
-    const size_t kMsgSize[5] = {12, 144, 1728, 20736, 248832};
-    const int kMessageCount[5] = {50000, 50000, 50000, 12000, 1000};
-
-    for (size_t i = 0; i < 5; i++) {
-      SetUpMeasurement(kMessageCount[i], kMsgSize[i]);
-      Measure(h);
-    }
-
-    SendQuitMessage(h);
+    RunPingPongServer(h);
   END_CHILD()
 }
 
diff --git a/mojo/edk/system/ports/node.cc b/mojo/edk/system/ports/node.cc
index 3324397..40b8325 100644
--- a/mojo/edk/system/ports/node.cc
+++ b/mojo/edk/system/ports/node.cc
@@ -301,6 +301,7 @@
   }
 
   Port* port = port_ref.port();
+  NodeName peer_node_name;
   {
     // We must acquire |ports_lock_| before grabbing any port locks, because
     // WillSendMessage_Locked may need to lock multiple ports out of order.
@@ -322,10 +323,12 @@
     // do to recover. Assume that failure beyond this point must be treated as a
     // transport failure.
 
-    if (port->peer_node_name != name_) {
-      delegate_->ForwardMessage(port->peer_node_name, std::move(m));
-      return OK;
-    }
+    peer_node_name = port->peer_node_name;
+  }
+
+  if (peer_node_name != name_) {
+    delegate_->ForwardMessage(peer_node_name, std::move(m));
+    return OK;
   }
 
   int rv = AcceptMessage(std::move(m));
@@ -367,6 +370,7 @@
                      const NodeName& destination_node_name,
                      const PortName& destination_port_name) {
   Port* port = port_ref.port();
+  MergePortEventData data;
   {
     // |ports_lock_| must be held for WillSendPort_Locked below.
     base::AutoLock ports_lock(ports_lock_);
@@ -377,15 +381,14 @@
 
     // Send the port-to-merge over to the destination node so it can be merged
     // into the port cycle atomically there.
-    MergePortEventData data;
     data.new_port_name = port_ref.name();
     WillSendPort_Locked(port, destination_node_name, &data.new_port_name,
                         &data.new_port_descriptor);
-    delegate_->ForwardMessage(
-        destination_node_name,
-        NewInternalMessage(destination_port_name,
-                           EventType::kMergePort, data));
   }
+  delegate_->ForwardMessage(
+      destination_node_name,
+      NewInternalMessage(destination_port_name,
+                         EventType::kMergePort, data));
   return OK;
 }
 
@@ -691,6 +694,9 @@
   // ObserveProxyAck.
 
   bool notify_delegate = false;
+  ObserveClosureEventData forwarded_data;
+  NodeName peer_node_name;
+  PortName peer_port_name;
   {
     // We must acquire |ports_lock_| before the port lock because it must be
     // held for MaybeRemoveProxy_Locked.
@@ -710,8 +716,6 @@
     // cares about it. This ensures that any dead-end proxies beyond that port
     // are notified to remove themselves.
 
-    ObserveClosureEventData forwarded_data;
-
     if (port->state == Port::kReceiving) {
       notify_delegate = true;
 
@@ -741,11 +745,14 @@
              << " (last_sequence_num=" << forwarded_data.last_sequence_num
              << ")";
 
-    delegate_->ForwardMessage(
-        port->peer_node_name,
-        NewInternalMessage(port->peer_port_name,
-                           EventType::kObserveClosure, forwarded_data));
+    peer_node_name = port->peer_node_name;
+    peer_port_name = port->peer_port_name;
   }
+  delegate_->ForwardMessage(
+      peer_node_name,
+      NewInternalMessage(peer_port_name, EventType::kObserveClosure,
+                         forwarded_data));
+
   if (notify_delegate) {
     PortRef port_ref(port_name, port);
     delegate_->PortStatusChanged(port_ref);
diff --git a/net/android/junit/src/org/chromium/net/HttpNegotiateAuthenticatorTest.java b/net/android/junit/src/org/chromium/net/HttpNegotiateAuthenticatorTest.java
index de211a1..09485e3 100644
--- a/net/android/junit/src/org/chromium/net/HttpNegotiateAuthenticatorTest.java
+++ b/net/android/junit/src/org/chromium/net/HttpNegotiateAuthenticatorTest.java
@@ -98,7 +98,7 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        ContextUtils.initApplicationContextForJUnitTests(Robolectric.application);
+        ContextUtils.initApplicationContextForTests(Robolectric.application);
     }
 
     @After
diff --git a/net/spdy/spdy_protocol.h b/net/spdy/spdy_protocol.h
index d66cddd0..aefc341 100644
--- a/net/spdy/spdy_protocol.h
+++ b/net/spdy/spdy_protocol.h
@@ -55,6 +55,10 @@
 // the maximum control frame size we accept.
 const uint32_t kSpdyInitialFrameSizeLimit = 1 << 14;
 
+// The initial value for the maximum size of the header list, "unlimited" (max
+// unsigned 32-bit int) as per the spec.
+const uint32_t kSpdyInitialHeaderListSizeLimit = 0xFFFFFFFF;
+
 // Maximum window size for a Spdy stream or session.
 const int32_t kSpdyMaximumWindowSize = 0x7FFFFFFF;  // Max signed 32bit int
 
diff --git a/remoting/android/host/src/org/chromium/chromoting/host/jni/Host.java b/remoting/android/host/src/org/chromium/chromoting/host/jni/Host.java
index e5aff2375..04c3857e9 100644
--- a/remoting/android/host/src/org/chromium/chromoting/host/jni/Host.java
+++ b/remoting/android/host/src/org/chromium/chromoting/host/jni/Host.java
@@ -30,8 +30,9 @@
      * @param context The Application context.
      */
     public static void loadLibrary(Context context) {
+        ContextUtils.initApplicationContext(context.getApplicationContext());
         System.loadLibrary("remoting_host_jni");
-        ContextUtils.initApplicationContext(context);
+        ContextUtils.initApplicationContextForNative();
     }
 
     public Host() {
diff --git a/remoting/android/java/src/org/chromium/chromoting/jni/JniInterface.java b/remoting/android/java/src/org/chromium/chromoting/jni/JniInterface.java
index 95b1671..47a8d2b 100644
--- a/remoting/android/java/src/org/chromium/chromoting/jni/JniInterface.java
+++ b/remoting/android/java/src/org/chromium/chromoting/jni/JniInterface.java
@@ -25,9 +25,9 @@
      * @param context The Application context.
      */
     public static void loadLibrary(Context context) {
+        ContextUtils.initApplicationContext(context.getApplicationContext());
         System.loadLibrary("remoting_client_jni");
-
-        ContextUtils.initApplicationContext(context);
+        ContextUtils.initApplicationContextForNative();
         nativeLoadNative();
     }
 
diff --git a/skia/ext/benchmarking_canvas.cc b/skia/ext/benchmarking_canvas.cc
index 1160b18..cccedd0 100644
--- a/skia/ext/benchmarking_canvas.cc
+++ b/skia/ext/benchmarking_canvas.cc
@@ -18,7 +18,6 @@
 #include "third_party/skia/include/core/SkRRect.h"
 #include "third_party/skia/include/core/SkRegion.h"
 #include "third_party/skia/include/core/SkString.h"
-#include "third_party/skia/include/core/SkTLazy.h"
 #include "third_party/skia/include/core/SkTextBlob.h"
 #include "third_party/skia/include/core/SkXfermode.h"
 
@@ -453,14 +452,13 @@
 
 class BenchmarkingCanvas::AutoOp {
 public:
+  // AutoOp objects are always scoped within draw call frames,
+  // so the paint is guaranteed to be valid for their lifetime.
   AutoOp(BenchmarkingCanvas* canvas, const char op_name[],
          const SkPaint* paint = nullptr)
       : canvas_(canvas)
       , op_record_(new base::DictionaryValue())
-      , op_params_(new base::ListValue())
-      // AutoOp objects are always scoped within draw call frames,
-      // so the paint is guaranteed to be valid for their lifetime.
-      , paint_(paint) {
+      , op_params_(new base::ListValue()) {
 
     DCHECK(canvas);
     DCHECK(op_name);
@@ -468,15 +466,16 @@
     op_record_->SetString("cmd_string", op_name);
     op_record_->Set("info", op_params_);
 
-    if (paint)
+    if (paint) {
       this->addParam("paint", AsValue(*paint));
+      filtered_paint_ = *paint;
+    }
 
     if (canvas->flags_ & kOverdrawVisualization_Flag) {
       DCHECK(canvas->overdraw_xfermode_);
 
-      paint_ = paint ? filtered_paint_.set(*paint) : filtered_paint_.init();
-      filtered_paint_.get()->setXfermode(canvas->overdraw_xfermode_);
-      filtered_paint_.get()->setAntiAlias(false);
+      filtered_paint_.setXfermode(canvas->overdraw_xfermode_);
+      filtered_paint_.setAntiAlias(false);
     }
 
     start_ticks_ = base::TimeTicks::Now();
@@ -496,7 +495,7 @@
     op_params_->Append(param.release());
   }
 
-  const SkPaint* paint() const { return paint_; }
+  const SkPaint* paint() const { return &filtered_paint_; }
 
 private:
   BenchmarkingCanvas* canvas_;
@@ -504,8 +503,7 @@
   base::ListValue* op_params_;
   base::TimeTicks start_ticks_;
 
-  const SkPaint* paint_;
-  SkTLazy<SkPaint> filtered_paint_;
+  SkPaint filtered_paint_;
 };
 
 BenchmarkingCanvas::BenchmarkingCanvas(SkCanvas* canvas, unsigned flags)
diff --git a/testing/android/native_test/java/src/org/chromium/native_test/NativeUnitTestActivity.java b/testing/android/native_test/java/src/org/chromium/native_test/NativeUnitTestActivity.java
index c708549..8411583 100644
--- a/testing/android/native_test/java/src/org/chromium/native_test/NativeUnitTestActivity.java
+++ b/testing/android/native_test/java/src/org/chromium/native_test/NativeUnitTestActivity.java
@@ -6,6 +6,7 @@
 
 import android.os.Bundle;
 
+import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
 import org.chromium.base.PathUtils;
 import org.chromium.base.PowerMonitor;
@@ -29,6 +30,7 @@
         // Needed by system_monitor_unittest.cc
         PowerMonitor.createForTests(this);
 
+        ContextUtils.initApplicationContext(getApplicationContext());
         loadLibraries();
     }
 
@@ -38,5 +40,6 @@
             System.loadLibrary(library);
             Log.i(TAG, "loaded: %s", library);
         }
+        ContextUtils.initApplicationContextForNative();
     }
 }
diff --git a/testing/android/native_test/native_test_launcher.cc b/testing/android/native_test/native_test_launcher.cc
index eb652d99..0f880a74 100644
--- a/testing/android/native_test/native_test_launcher.cc
+++ b/testing/android/native_test/native_test_launcher.cc
@@ -75,10 +75,6 @@
   static const char* const kInitialArgv[] = { "ChromeTestActivity" };
   base::CommandLine::Init(arraysize(kInitialArgv), kInitialArgv);
 
-  // Set the application context in base.
-  base::android::RegisterJni(env);
-  base::android::InitApplicationContext(env, app_context);
-
   std::vector<std::string> args;
 
   const std::string command_line_file_path(
@@ -133,6 +129,9 @@
 }
 
 bool RegisterNativeTestJNI(JNIEnv* env) {
+  if (!base::android::RegisterJni(env)) {
+    return false;
+  }
   return RegisterNativesImpl(env);
 }
 
diff --git a/testing/libfuzzer/fuzzers/BUILD.gn b/testing/libfuzzer/fuzzers/BUILD.gn
index 0ca391d..a302af47 100644
--- a/testing/libfuzzer/fuzzers/BUILD.gn
+++ b/testing/libfuzzer/fuzzers/BUILD.gn
@@ -219,6 +219,7 @@
     "//v8:parser_fuzzer",
   ]
   dict = "dicts/js.dict"
+  seed_corpus = "//v8/test/mjsunit/regress/"
 }
 
 fuzzer_test("v8_json_parser_fuzzer") {
diff --git a/testing/variations/fieldtrial_testing_config_win.json b/testing/variations/fieldtrial_testing_config_win.json
index f1cb787..06e995291 100644
--- a/testing/variations/fieldtrial_testing_config_win.json
+++ b/testing/variations/fieldtrial_testing_config_win.json
@@ -193,10 +193,16 @@
     ],
     "PreRead": [
         {
-            "group_name": "NoPrefetchArgument",
+            "group_name": "NoPrefetchArgument2",
             "params": {
                 "NoPrefetchArgument": "true"
             }
+        },
+        {
+            "group_name": "PreReadChromeChildInBrowser",
+            "params": {
+                "PreReadChromeChildInBrowser": "true"
+            }
         }
     ],
     "QUIC": [
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process b/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process
index ab88eec..8e9ad9906 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process
@@ -20,8 +20,6 @@
 
 # Uninvestigated timeouts (possibly variants of https://crbug.com/584984)
 http/tests/history/cross-origin-redirect-on-back.html [ Timeout Crash ]
-http/tests/security/cross-frame-access-document-direct.html [ Crash Timeout ]
-http/tests/security/referrer-policy-origin-when-crossorigin-is-crossorigin.html [ Crash Timeout ]
 
 # https://crbug.com/582201 - missing console message about blocked XSS.
 http/tests/security/javascriptURL/javascriptURL-execution-context-frame-src-getAttribute-value.html [ Failure ]
@@ -86,9 +84,6 @@
 http/tests/security/mixedContent/insecure-eventsource-in-main-frame.html [ Failure ]
 
 # Uninvestigated failures under http/tests/security:
-http/tests/security/cookies/third-party-cookie-blocking.html [ Timeout ]
-http/tests/security/cookies/third-party-cookie-blocking-user-action.html [ Timeout ]
-http/tests/security/cross-frame-access-delete.html [ Timeout ]
 http/tests/security/cross-frame-access-enumeration.html [ Timeout ]
 http/tests/security/cross-frame-access-get-custom-property-cached.html [ Timeout ]
 http/tests/security/cross-frame-access-get.html [ Timeout ]
@@ -96,34 +91,21 @@
 http/tests/security/cross-frame-access-getOwnPropertyDescriptor.html [ Timeout ]
 http/tests/security/cross-frame-access-location-get.html [ Timeout ]
 http/tests/security/cross-frame-access-location-get-override.html [ Timeout ]
-http/tests/security/cross-frame-access-location-put.html [ Timeout ]
-http/tests/security/cross-frame-access-object-prototype.html [ Timeout ]
 http/tests/security/cross-origin-shared-worker-allowed.html [ Failure Timeout ]
 http/tests/security/cross-origin-worker-indexeddb-allowed.html [ Failure Timeout ]
-http/tests/security/dataURL/xss-DENIED-from-data-url-in-foreign-domain-subframe.html [ Timeout ]
-http/tests/security/drag-drop-different-origin.html [ Timeout ]
 http/tests/security/frameNavigation/not-opener.html [ Timeout ]
 http/tests/security/frameNavigation/xss-DENIED-targeted-link-navigation.html [ Timeout ]
-http/tests/security/host-compare-case-insensitive.html [ Timeout ]
-http/tests/security/mixedContent/insecure-css-image-with-reload.html [ Timeout ]
-http/tests/security/mixedContent/insecure-xhr-in-main-frame.html [ Timeout ]
 http/tests/security/referrer-policy-redirect-link.html [ Timeout ]
-http/tests/security/window-events-clear-domain.html [ Timeout ]
-http/tests/security/xssAuditor/anchor-url-dom-write-location-javascript-URL.html [ Timeout ]
-http/tests/security/xssAuditor/dom-write-location-javascript-URL.html [ Timeout ]
-http/tests/security/xssAuditor/get-from-iframe.html [ Timeout ]
-http/tests/security/xssAuditor/link-opens-new-window.html [ Timeout ]
-http/tests/security/xssAuditor/post-from-iframe.html [ Timeout ]
-http/tests/security/xssAuditor/script-tag-post-control-char.html [ Timeout ]
-http/tests/security/xssAuditor/script-tag-post.html [ Timeout ]
-http/tests/security/xssAuditor/script-tag-post-null-char.html [ Failure Timeout ]
-http/tests/security/xssAuditor/script-tag-post-redirect.html [ Timeout ]
+http/tests/security/xssAuditor/post-from-iframe.html [ Failure ]
+http/tests/security/xssAuditor/script-tag-post-control-char.html [ Failure ]
+http/tests/security/xssAuditor/script-tag-post.html [ Failure ]
+http/tests/security/xssAuditor/script-tag-post-null-char.html [ Failure ]
 http/tests/security/xssAuditor/script-tag-with-callbacks.html [ Failure ]
-http/tests/security/xssAuditor/xss-filter-bypass-long-string.html [ Timeout ]
+http/tests/security/xssAuditor/xss-filter-bypass-long-string.html [ Failure ]
 
 # Uninvestigated failures under http/tests (but outside of http/tests/security):
 http/tests/appcache/remove-cache.html [ Failure ]
-http/tests/inspector-protocol/access-inspected-object.html [ Timeout Failure ]
+http/tests/inspector-protocol/access-inspected-object.html [ Failure ]
 http/tests/inspector/injected-script-for-origin.html [ Failure ]
 http/tests/local/serviceworker/fetch-request-body-file.html [ Failure Crash ]
 http/tests/inspector-protocol/request-mixed-content-status-blockable.html [ Timeout ]
@@ -148,4 +130,3 @@
 http/tests/w3c/webperf/submission/Intel/resource-timing/test_resource_timing_cross_origin_redirect_with_timing_allow_origin.html [ Timeout ]
 http/tests/w3c/webperf/submission/Intel/resource-timing/test_resource_timing_cross_origin_resource_request.html [ Timeout ]
 http/tests/w3c/webperf/submission/Intel/resource-timing/test_resource_timing_timing_allow_cross_origin_resource_request.html [ Timeout ]
-http/tests/workers/shared-worker-secure-context.https.html [ Timeout ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index c5d54c2..32893c0 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -543,9 +543,6 @@
 
 crbug.com/542660 fast/css/absolute-inline-alignment-2.html [ Failure ]
 
-crbug.com/603997 compositing/overflow/clear-scroll-parent.html [ NeedsManualRebaseline ]
-crbug.com/603997 virtual/prefer_compositing_to_lcd_text/compositing/overflow/clear-scroll-parent.html [ NeedsManualRebaseline ]
-
 # Ref tests that needs investigation.
 crbug.com/404597 [ Mac ] fast/css3-text/css3-text-justify/text-justify-crash.html [ Failure ]
 crbug.com/404597 fast/forms/long-text-in-input.html [ Failure ]
@@ -1049,11 +1046,6 @@
 
 crbug.com/548695 fast/forms/datalist/update-range-with-datalist.html [ Failure ]
 
-crbug.com/607259 [ Win ] css2.1/t1508-c527-font-08-b.html [ NeedsManualRebaseline ]
-crbug.com/607259 [ Win ] css2.1/t1504-c523-font-style-00-b.html [ NeedsManualRebaseline ]
-crbug.com/607259 [ Win ] css1/font_properties/font_style.html [ NeedsManualRebaseline ]
-crbug.com/607259 [ Win ] svg/batik/text/textStyles.svg [ NeedsManualRebaseline ]
-
 # Temporarily disabled after chromium change
 crbug.com/492511 [ Mac ] fast/text/atsui-negative-spacing-features.html [ Failure ]
 crbug.com/492511 [ Mac ] fast/text/international/arabic-justify.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/clear-scroll-parent-expected.txt b/third_party/WebKit/LayoutTests/compositing/overflow/clear-scroll-parent-expected.txt
index 82736418..a7e022e7 100644
--- a/third_party/WebKit/LayoutTests/compositing/overflow/clear-scroll-parent-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/clear-scroll-parent-expected.txt
@@ -47,13 +47,13 @@
           "backgroundColor": "#008000"
         },
         {
-          "position": [12, 12],
+          "position": [4, 4],
           "bounds": [80, 80],
           "shouldFlattenTransform": false,
           "hasScrollParent": true,
           "children": [
             {
-              "position": [10, 10],
+              "position": [18, 18],
               "bounds": [100, 100],
               "contentsOpaque": true,
               "drawsContent": true,
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-getContext2D-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-getContext-expected.txt
similarity index 91%
rename from third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-getContext2D-expected.txt
rename to third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-getContext-expected.txt
index 6894f5c0..e78be60 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-getContext2D-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-getContext-expected.txt
@@ -13,7 +13,7 @@
 PASS ctx2 is null
 PASS ctx3 is non-null.
 PASS ctx3 == ctx is true
-PASS bogusCtx is null
+PASS ctx4 is an instance of WebGLRenderingContext
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-getContext2D-in-worker-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-getContext-in-worker-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-getContext2D-in-worker-expected.txt
rename to third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-getContext-in-worker-expected.txt
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-getContext2D-in-worker.html b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-getContext-in-worker.html
similarity index 72%
rename from third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-getContext2D-in-worker.html
rename to third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-getContext-in-worker.html
index e555fa9..91a3fd0 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-getContext2D-in-worker.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-getContext-in-worker.html
@@ -5,10 +5,15 @@
 <script id="myWorker" type="text/worker">
 self.onmessage = function(e) {
     var aCanvas = new OffscreenCanvas(50, 50);
+    var bCanvas = new OffscreenCanvas(50, 50);
     try {
-      var ctx = aCanvas.getContext('2d');
-      if (toString.call(ctx) != '[object OffscreenCanvasRenderingContext2D]') {
+      var ctx1 = aCanvas.getContext('2d');
+      //TODO(crbug.com/602391): implement get webgl context in worker
+      var ctx2 = bCanvas.getContext('webgl');
+      if (toString.call(ctx1) != '[object OffscreenCanvasRenderingContext2D]') {
           self.postMessage("aCanvas.getContext('2d') does not return [object OffscreenCanvasRenderingContext2D]");
+      } else if (toString.call(ctx2) != '[object Null]') {
+          self.postMessage("bCanvas.getContext('webgl') does not return [object Null]");
       } else {
           self.postMessage("success");
       }
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-getContext2D.html b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-getContext.html
similarity index 89%
rename from third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-getContext2D.html
rename to third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-getContext.html
index be7fad2..786b1c8 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-getContext2D.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-getContext.html
@@ -32,7 +32,7 @@
 
 // TODO: change the below part of the test when webgl is supported.
 // Calling getContext on an unimplemented context type will return null
-var bogusCanvas = new OffscreenCanvas(20, 20);
-var bogusCtx = bogusCanvas.getContext("webgl");
-shouldBeNull("bogusCtx");
+var bCanvas = new OffscreenCanvas(20, 20);
+var ctx4 = bCanvas.getContext("webgl");
+shouldBeType("ctx4", "WebGLRenderingContext");
 </script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-ImageBitmap-close-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-ImageBitmap-close-expected.txt
index 26836ff4..736ae1b 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-ImageBitmap-close-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-ImageBitmap-close-expected.txt
@@ -9,9 +9,9 @@
 PASS bitmap.height is imgHeight
 PASS bitmap.width is 0
 PASS bitmap.height is 0
-PASS ctx.drawImage(bitmap, 0, 0) threw exception InvalidStateError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The image source is neutered.
-PASS Apply structured clone to an already closed bitmap is rejected as expected: DataCloneError: Failed to execute 'postMessage' on 'Worker': An ImageBitmap is neutered and could not be cloned.
-PASS Apply transfering to an already closed bitmap is rejected as expected: DataCloneError: Failed to execute 'postMessage' on 'Worker': An ImageBitmap is neutered and could not be cloned.
+PASS ctx.drawImage(bitmap, 0, 0) threw exception InvalidStateError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The image source is detached.
+PASS Apply structured clone to an already closed bitmap is rejected as expected: DataCloneError: Failed to execute 'postMessage' on 'Worker': An ImageBitmap is detached and could not be cloned.
+PASS Apply transfering to an already closed bitmap is rejected as expected: DataCloneError: Failed to execute 'postMessage' on 'Worker': An ImageBitmap is detached and could not be cloned.
 PASS createImageBitmap from a closed ImageBitmap was rejected. IndexSizeError: Failed to execute 'createImageBitmap' on 'Window': The source width provided is 0.
 PASS bitmap.width is 0
 PASS bitmap.height is 0
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-ImageBitmap-transferable-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-ImageBitmap-transferable-expected.txt
index 699627a7..17a76da 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-ImageBitmap-transferable-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-ImageBitmap-transferable-expected.txt
@@ -7,7 +7,7 @@
 PASS bitmapHeight is imageHeight
 PASS bitmapWidth is 0
 PASS bitmapHeight is 0
-PASS Apply structured cloning to a neutered ImageBitmap should throw an exception: DataCloneError: Failed to execute 'postMessage' on 'Worker': An ImageBitmap is neutered and could not be cloned.
+PASS Apply structured cloning to a neutered ImageBitmap should throw an exception: DataCloneError: Failed to execute 'postMessage' on 'Worker': An ImageBitmap is detached and could not be cloned.
 PASS createImageBitmap from a neutered ImageBitmap was rejected
 PASS bitmapWidth is imageWidth
 PASS bitmapHeight is imageHeight
diff --git a/third_party/WebKit/LayoutTests/fast/dom/SelectorAPI/namespaced-elements-and-selectors-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/SelectorAPI/namespaced-elements-and-selectors-expected.txt
new file mode 100644
index 0000000..22a2eb7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/dom/SelectorAPI/namespaced-elements-and-selectors-expected.txt
@@ -0,0 +1,12 @@
+querySelectorAll and namespaces
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS sandbox.querySelectorAll('span').length is 3
+PASS sandbox.querySelectorAll('*|span').length is 3
+PASS sandbox.querySelectorAll('|span').length is 1
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/WebKit/LayoutTests/fast/dom/SelectorAPI/namespaced-elements-and-selectors.html b/third_party/WebKit/LayoutTests/fast/dom/SelectorAPI/namespaced-elements-and-selectors.html
new file mode 100644
index 0000000..2f5a54e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/dom/SelectorAPI/namespaced-elements-and-selectors.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<script src="../../../resources/js-test.js"></script>
+<div id="sandbox">
+    <span></span>
+</div>
+<script>
+description("querySelectorAll and namespaces");
+
+sandbox.appendChild(document.createElementNS("http://dummynamespace", "span"));
+sandbox.appendChild(document.createElementNS("", "span"));
+
+shouldBe("sandbox.querySelectorAll('span').length", "3");
+shouldBe("sandbox.querySelectorAll('*|span').length", "3");
+shouldBe("sandbox.querySelectorAll('|span').length", "1");
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/loading/redirect-methods.html b/third_party/WebKit/LayoutTests/http/tests/loading/redirect-methods.html
index 55e2cdb..39abd27 100644
--- a/third_party/WebKit/LayoutTests/http/tests/loading/redirect-methods.html
+++ b/third_party/WebKit/LayoutTests/http/tests/loading/redirect-methods.html
@@ -33,8 +33,14 @@
     var iframe = document.getElementById(frameID);
     if (iframe.hasAttribute("submitted")) {
         if (++frameID == testCodes.length) {
-            if (window.testRunner)
-                testRunner.notifyDone();
+            if (window.testRunner) {
+                // Before finishing the test, we have to allow the callstack to
+                // unwind - this enables dumping of pending WebFrameClient
+                // callbacks (i.e. didFinishLoad and/or didHandleOnloadEvents).
+                window.setTimeout(function() {
+                    testRunner.notifyDone();
+                }, 0);
+            }
             return;
         }
         createFrame(frameID);
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/scripthash-handler-allowed.html b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/scripthash-handler-allowed.html
index b73cc17..e37a963e 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/scripthash-handler-allowed.html
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/scripthash-handler-allowed.html
@@ -24,7 +24,7 @@
             }, 'Inline event handlers not whitelisted by the policy should generate error events.');
         </script>
 
-        <meta http-equiv="Content-Security-Policy" content="script-src 'sha256-nhtYaXCssBJTThiDLYewspQYue9tisulEwJ3nTJKcMI='">
+        <meta http-equiv="Content-Security-Policy" content="script-src 'sha256-nhtYaXCssBJTThiDLYewspQYue9tisulEwJ3nTJKcMI=' 'unsafe-hashed-attributes'">
     </head>
     <body>
         <button id="pass" onclick="expectSuccess(this)"></button>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/scripthash-handler-blocked.html b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/scripthash-handler-blocked.html
new file mode 100644
index 0000000..b5e21d1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/scripthash-handler-blocked.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script>
+            async_test(function (t) {
+                window.expectSuccess = t.unreached_func("Handler should not execute.");
+                window.addEventListener('load', t.step_func(function () {
+                    document.querySelector('#pass').click();
+                }));
+                document.addEventListener('securitypolicyviolation', t.step_func_done(function (e) {
+                    assert_equals(e.target, document);
+                }));
+            }, 'Inline event handlers whitelisted by the policy should not fire, as \'unsafe-hash-attributes\' is not present.');
+        </script>
+
+        <meta http-equiv="Content-Security-Policy" content="script-src 'sha256-nhtYaXCssBJTThiDLYewspQYue9tisulEwJ3nTJKcMI='">
+    </head>
+    <body>
+        <button id="pass" onclick="expectFailure(this)"></button>
+        <button id="fail" onclick="expectFailure(this)"></button>
+    </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/dom/events/Event-propagation-expected.txt b/third_party/WebKit/LayoutTests/imported/web-platform-tests/dom/events/Event-propagation-expected.txt
deleted file mode 100644
index 991c91f..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/dom/events/Event-propagation-expected.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-This is a testharness.js-based test.
-PASS Newly-created Event 
-PASS After stopPropagation() 
-FAIL Reinitialized after stopPropagation() assert_equals: Propagation flag expected true but got false
-PASS After stopImmediatePropagation() 
-FAIL Reinitialized after stopImmediatePropagation() assert_equals: Propagation flag expected true but got false
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/platform/android/compositing/overflow/clear-scroll-parent-expected.txt b/third_party/WebKit/LayoutTests/platform/android/compositing/overflow/clear-scroll-parent-expected.txt
new file mode 100644
index 0000000..82736418
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/compositing/overflow/clear-scroll-parent-expected.txt
@@ -0,0 +1,86 @@
+{
+  "bounds": [800, 600],
+  "children": [
+    {
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "children": [
+        {
+          "position": [8, 8],
+          "bounds": [308, 208],
+          "shouldFlattenTransform": false,
+          "drawsContent": true,
+          "children": [
+            {
+              "position": [4, 4],
+              "bounds": [285, 200],
+              "shouldFlattenTransform": false,
+              "children": [
+                {
+                  "bounds": [285, 530],
+                  "drawsContent": true
+                }
+              ]
+            },
+            {
+              "bounds": [308, 208],
+              "children": [
+                {
+                  "position": [289, 4],
+                  "bounds": [15, 185]
+                },
+                {
+                  "position": [289, 189],
+                  "bounds": [15, 15],
+                  "drawsContent": true
+                }
+              ]
+            }
+          ]
+        },
+        {
+          "position": [50, 200],
+          "bounds": [200, 200],
+          "contentsOpaque": true,
+          "drawsContent": true,
+          "backgroundColor": "#008000"
+        },
+        {
+          "position": [12, 12],
+          "bounds": [80, 80],
+          "shouldFlattenTransform": false,
+          "hasScrollParent": true,
+          "children": [
+            {
+              "position": [10, 10],
+              "bounds": [100, 100],
+              "contentsOpaque": true,
+              "drawsContent": true,
+              "backgroundColor": "#FF0000"
+            }
+          ]
+        },
+        {
+          "shouldFlattenTransform": false,
+          "hasScrollParent": true,
+          "children": [
+            {
+              "position": [22, 102],
+              "bounds": [100, 100],
+              "contentsOpaque": true,
+              "drawsContent": true,
+              "backgroundColor": "#0000FF"
+            },
+            {
+              "position": [22, 212],
+              "bounds": [100, 320],
+              "drawsContent": true
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/android/virtual/prefer_compositing_to_lcd_text/compositing/overflow/clear-scroll-parent-expected.txt b/third_party/WebKit/LayoutTests/platform/android/virtual/prefer_compositing_to_lcd_text/compositing/overflow/clear-scroll-parent-expected.txt
new file mode 100644
index 0000000..82736418
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/virtual/prefer_compositing_to_lcd_text/compositing/overflow/clear-scroll-parent-expected.txt
@@ -0,0 +1,86 @@
+{
+  "bounds": [800, 600],
+  "children": [
+    {
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "children": [
+        {
+          "position": [8, 8],
+          "bounds": [308, 208],
+          "shouldFlattenTransform": false,
+          "drawsContent": true,
+          "children": [
+            {
+              "position": [4, 4],
+              "bounds": [285, 200],
+              "shouldFlattenTransform": false,
+              "children": [
+                {
+                  "bounds": [285, 530],
+                  "drawsContent": true
+                }
+              ]
+            },
+            {
+              "bounds": [308, 208],
+              "children": [
+                {
+                  "position": [289, 4],
+                  "bounds": [15, 185]
+                },
+                {
+                  "position": [289, 189],
+                  "bounds": [15, 15],
+                  "drawsContent": true
+                }
+              ]
+            }
+          ]
+        },
+        {
+          "position": [50, 200],
+          "bounds": [200, 200],
+          "contentsOpaque": true,
+          "drawsContent": true,
+          "backgroundColor": "#008000"
+        },
+        {
+          "position": [12, 12],
+          "bounds": [80, 80],
+          "shouldFlattenTransform": false,
+          "hasScrollParent": true,
+          "children": [
+            {
+              "position": [10, 10],
+              "bounds": [100, 100],
+              "contentsOpaque": true,
+              "drawsContent": true,
+              "backgroundColor": "#FF0000"
+            }
+          ]
+        },
+        {
+          "shouldFlattenTransform": false,
+          "hasScrollParent": true,
+          "children": [
+            {
+              "position": [22, 102],
+              "bounds": [100, 100],
+              "contentsOpaque": true,
+              "drawsContent": true,
+              "backgroundColor": "#0000FF"
+            },
+            {
+              "position": [22, 212],
+              "bounds": [100, 320],
+              "drawsContent": true
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/suggestion-picker/month-suggestion-picker-appearance-with-scroll-bar-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/suggestion-picker/month-suggestion-picker-appearance-with-scroll-bar-expected.png
index 3d61b46..ca8d067 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/suggestion-picker/month-suggestion-picker-appearance-with-scroll-bar-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/suggestion-picker/month-suggestion-picker-appearance-with-scroll-bar-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/suggestion-picker/time-suggestion-picker-appearance-rtl-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/suggestion-picker/time-suggestion-picker-appearance-rtl-expected.png
index 2e00afc..a5c0196 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/suggestion-picker/time-suggestion-picker-appearance-rtl-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/suggestion-picker/time-suggestion-picker-appearance-rtl-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/css1/font_properties/font_style-expected.png b/third_party/WebKit/LayoutTests/platform/win/css1/font_properties/font_style-expected.png
index bc4eb9a..73c037e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css1/font_properties/font_style-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/css1/font_properties/font_style-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/css2.1/t1504-c523-font-style-00-b-expected.png b/third_party/WebKit/LayoutTests/platform/win/css2.1/t1504-c523-font-style-00-b-expected.png
index c4df9b8..5b787c1d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css2.1/t1504-c523-font-style-00-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/css2.1/t1504-c523-font-style-00-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/css2.1/t1508-c527-font-08-b-expected.png b/third_party/WebKit/LayoutTests/platform/win/css2.1/t1508-c527-font-08-b-expected.png
index 93a5f79a5..c3dd5ff 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css2.1/t1508-c527-font-08-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/css2.1/t1508-c527-font-08-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/batik/text/textStyles-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/batik/text/textStyles-expected.png
index cc6aec7a..7d89179 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/batik/text/textStyles-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/batik/text/textStyles-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/batik/text/textStyles-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/batik/text/textStyles-expected.txt
index 8e3e8824..eba396f 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/batik/text/textStyles-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/batik/text/textStyles-expected.txt
@@ -29,10 +29,10 @@
         LayoutSVGText {text} at (-36,3) size 72x15 contains 1 chunk(s)
           LayoutSVGInlineText {#text} at (0,0) size 71x15
             chunk 1 (middle anchor) text run 1 at (-35.50,15.00) startOffset 0 endOffset 15 width 71.00: "SansSerif, bold"
-      LayoutSVGContainer {g} at (307,83) size 88x45 [transform={m=((1.00,0.00)(0.00,1.00)) t=(350.00,110.00)}]
-        LayoutSVGContainer {use} at (307,83) size 88x34
-          LayoutSVGText {text} at (-43,-27) size 88x34 contains 1 chunk(s)
-            LayoutSVGInlineText {#text} at (0,0) size 87x34
+      LayoutSVGContainer {g} at (307,83) size 89x45 [transform={m=((1.00,0.00)(0.00,1.00)) t=(350.00,110.00)}]
+        LayoutSVGContainer {use} at (307,83) size 89x34
+          LayoutSVGText {text} at (-43,-27) size 89x34 contains 1 chunk(s)
+            LayoutSVGInlineText {#text} at (0,0) size 88x34
               chunk 1 (middle anchor) text run 1 at (-42.49,0.00) startOffset 0 endOffset 6 width 84.98: "sample"
         LayoutSVGText {text} at (-43,3) size 86x15 contains 1 chunk(s)
           LayoutSVGInlineText {#text} at (0,0) size 85x15
@@ -53,10 +53,10 @@
         LayoutSVGText {text} at (-25,3) size 50x15 contains 1 chunk(s)
           LayoutSVGInlineText {#text} at (0,0) size 49x15
             chunk 1 (middle anchor) text run 1 at (-24.50,15.00) startOffset 0 endOffset 11 width 49.00: "Serif, bold"
-      LayoutSVGContainer {g} at (307,133) size 88x45 [transform={m=((1.00,0.00)(0.00,1.00)) t=(350.00,160.00)}]
-        LayoutSVGContainer {use} at (307,133) size 88x34
-          LayoutSVGText {text} at (-43,-27) size 88x34 contains 1 chunk(s)
-            LayoutSVGInlineText {#text} at (0,0) size 87x34
+      LayoutSVGContainer {g} at (307,133) size 89x45 [transform={m=((1.00,0.00)(0.00,1.00)) t=(350.00,160.00)}]
+        LayoutSVGContainer {use} at (307,133) size 89x34
+          LayoutSVGText {text} at (-43,-27) size 89x34 contains 1 chunk(s)
+            LayoutSVGInlineText {#text} at (0,0) size 88x34
               chunk 1 (middle anchor) text run 1 at (-42.49,0.00) startOffset 0 endOffset 6 width 84.98: "sample"
         LayoutSVGText {text} at (-32,3) size 64x15 contains 1 chunk(s)
           LayoutSVGInlineText {#text} at (0,0) size 63x15
@@ -78,9 +78,9 @@
           LayoutSVGInlineText {#text} at (0,0) size 90x15
             chunk 1 (middle anchor) text run 1 at (-45.00,15.00) startOffset 0 endOffset 16 width 90.00: "Monospaced, bold"
       LayoutSVGContainer {g} at (298,183) size 104x45 [transform={m=((1.00,0.00)(0.00,1.00)) t=(350.00,210.00)}]
-        LayoutSVGContainer {use} at (307,183) size 88x34
-          LayoutSVGText {text} at (-43,-27) size 88x34 contains 1 chunk(s)
-            LayoutSVGInlineText {#text} at (0,0) size 87x34
+        LayoutSVGContainer {use} at (307,183) size 89x34
+          LayoutSVGText {text} at (-43,-27) size 89x34 contains 1 chunk(s)
+            LayoutSVGInlineText {#text} at (0,0) size 88x34
               chunk 1 (middle anchor) text run 1 at (-42.49,0.00) startOffset 0 endOffset 6 width 84.98: "sample"
         LayoutSVGText {text} at (-52,3) size 104x15 contains 1 chunk(s)
           LayoutSVGInlineText {#text} at (0,0) size 104x15
@@ -94,9 +94,9 @@
           LayoutSVGInlineText {#text} at (0,0) size 41x15
             chunk 1 (middle anchor) text run 1 at (-20.50,15.00) startOffset 0 endOffset 9 width 41.00: "(default)"
       LayoutSVGContainer {g} at (174,233) size 102x45 [transform={m=((1.00,0.00)(0.00,1.00)) t=(225.00,260.00)}]
-        LayoutSVGContainer {use} at (180,233) size 92x34
-          LayoutSVGText {text} at (-45,-27) size 92x34 contains 1 chunk(s)
-            LayoutSVGInlineText {#text} at (0,0) size 92x34
+        LayoutSVGContainer {use} at (180,233) size 93x34
+          LayoutSVGText {text} at (-45,-27) size 93x34 contains 1 chunk(s)
+            LayoutSVGInlineText {#text} at (0,0) size 93x34
               chunk 1 (middle anchor) text run 1 at (-45.00,0.00) startOffset 0 endOffset 6 width 90.00: "sample"
         LayoutSVGText {text} at (-51,3) size 102x15 contains 1 chunk(s)
           LayoutSVGInlineText {#text} at (0,0) size 101x15
diff --git a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/clear-scroll-parent-expected.txt b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/clear-scroll-parent-expected.txt
index 82736418..a7e022e7 100644
--- a/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/clear-scroll-parent-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/clear-scroll-parent-expected.txt
@@ -47,13 +47,13 @@
           "backgroundColor": "#008000"
         },
         {
-          "position": [12, 12],
+          "position": [4, 4],
           "bounds": [80, 80],
           "shouldFlattenTransform": false,
           "hasScrollParent": true,
           "children": [
             {
-              "position": [10, 10],
+              "position": [18, 18],
               "bounds": [100, 100],
               "contentsOpaque": true,
               "drawsContent": true,
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptValueSerializer.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptValueSerializer.cpp
index 94a19886..ce69fab 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptValueSerializer.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptValueSerializer.cpp
@@ -1053,7 +1053,7 @@
     if (!imageBitmap)
         return nullptr;
     if (imageBitmap->isNeutered())
-        return handleError(DataCloneError, "An ImageBitmap is neutered and could not be cloned.", next);
+        return handleError(DataCloneError, "An ImageBitmap is detached and could not be cloned.", next);
     OwnPtr<uint8_t[]> pixelData = imageBitmap->copyBitmapData(PremultiplyAlpha);
     m_writer.writeImageBitmap(imageBitmap->width(), imageBitmap->height(), pixelData.get(), imageBitmap->width() * imageBitmap->height() * 4);
     return nullptr;
@@ -1123,7 +1123,7 @@
     if (!imageBitmap)
         return 0;
     if (imageBitmap->isNeutered())
-        return handleError(DataCloneError, "An ImageBitmap is neutered and could not be cloned.", next);
+        return handleError(DataCloneError, "An ImageBitmap is detached and could not be cloned.", next);
     m_writer.writeTransferredImageBitmap(index);
     return 0;
 }
diff --git a/third_party/WebKit/Source/bindings/core/v8/SerializedScriptValue.cpp b/third_party/WebKit/Source/bindings/core/v8/SerializedScriptValue.cpp
index 43cc0f8..0863f1e 100644
--- a/third_party/WebKit/Source/bindings/core/v8/SerializedScriptValue.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/SerializedScriptValue.cpp
@@ -125,7 +125,7 @@
 
     for (size_t i = 0; i < imageBitmaps.size(); ++i) {
         if (imageBitmaps[i]->isNeutered()) {
-            exceptionState.throwDOMException(DataCloneError, "ImageBitmap at index " + String::number(i) + " is already neutered.");
+            exceptionState.throwDOMException(DataCloneError, "ImageBitmap at index " + String::number(i) + " is already detached.");
             return;
         }
     }
@@ -151,7 +151,7 @@
         if (visited.contains(offscreenCanvases[i].get()))
             continue;
         if (offscreenCanvases[i]->isNeutered()) {
-            exceptionState.throwDOMException(DataCloneError, "OffscreenCanvas at index " + String::number(i) + " is already neutered.");
+            exceptionState.throwDOMException(DataCloneError, "OffscreenCanvas at index " + String::number(i) + " is already detached.");
             return;
         }
         if (offscreenCanvases[i]->renderingContext()) {
diff --git a/third_party/WebKit/Source/bindings/core/v8/ToV8.h b/third_party/WebKit/Source/bindings/core/v8/ToV8.h
index 39ad5dd..3f4a9779 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ToV8.h
+++ b/third_party/WebKit/Source/bindings/core/v8/ToV8.h
@@ -198,11 +198,15 @@
 template<typename Sequence>
 inline v8::Local<v8::Value> toV8SequenceInternal(const Sequence& sequence, v8::Local<v8::Object> creationContext, v8::Isolate* isolate)
 {
-    v8::Local<v8::Array> array = v8::Array::New(isolate, sequence.size());
+    v8::Local<v8::Array> array;
+    {
+        v8::Context::Scope contextScope(creationContext->CreationContext());
+        array = v8::Array::New(isolate, sequence.size());
+    }
     uint32_t index = 0;
     typename Sequence::const_iterator end = sequence.end();
     for (typename Sequence::const_iterator iter = sequence.begin(); iter != end; ++iter) {
-        v8::Local<v8::Value> value = toV8(*iter, creationContext, isolate);
+        v8::Local<v8::Value> value = toV8(*iter, array, isolate);
         if (value.IsEmpty())
             value = v8::Undefined(isolate);
         if (!v8CallBoolean(array->Set(isolate->GetCurrentContext(), v8::Integer::New(isolate, index++), value)))
@@ -226,9 +230,13 @@
 template<typename T>
 inline v8::Local<v8::Value> toV8(const Vector<std::pair<String, T>>& value, v8::Local<v8::Object> creationContext, v8::Isolate* isolate)
 {
-    v8::Local<v8::Object> object = v8::Object::New(isolate);
+    v8::Local<v8::Object> object;
+    {
+        v8::Context::Scope contextScope(creationContext->CreationContext());
+        object = v8::Object::New(isolate);
+    }
     for (unsigned i = 0; i < value.size(); ++i) {
-        v8::Local<v8::Value> v8Value = toV8(value[i].second, creationContext, isolate);
+        v8::Local<v8::Value> v8Value = toV8(value[i].second, object, isolate);
         if (v8Value.IsEmpty())
             v8Value = v8::Undefined(isolate);
         if (!v8CallBoolean(object->Set(isolate->GetCurrentContext(), v8String(isolate, value[i].first), v8Value)))
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8LazyEventListener.cpp b/third_party/WebKit/Source/bindings/core/v8/V8LazyEventListener.cpp
index 58e0541..967857f 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8LazyEventListener.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8LazyEventListener.cpp
@@ -126,7 +126,7 @@
     if (!executionContext->isDocument())
         return;
 
-    if (!toDocument(executionContext)->allowInlineEventHandlers(m_node, this, m_sourceURL, m_position.m_line)) {
+    if (!toDocument(executionContext)->allowInlineEventHandler(m_node, this, m_sourceURL, m_position.m_line)) {
         clearListenerObject();
         return;
     }
diff --git a/third_party/WebKit/Source/core/core.gypi b/third_party/WebKit/Source/core/core.gypi
index 4bcfb1b..85f5b12 100644
--- a/third_party/WebKit/Source/core/core.gypi
+++ b/third_party/WebKit/Source/core/core.gypi
@@ -2694,7 +2694,6 @@
             'dom/shadow/SelectRuleFeatureSet.h',
             'dom/shadow/ShadowRoot.cpp',
             'dom/shadow/ShadowRoot.h',
-            'dom/shadow/ShadowRootRareData.h',
             'dom/shadow/ShadowRootRareDataV0.h',
             'dom/shadow/SlotAssignment.cpp',
             'dom/shadow/SlotAssignment.h',
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp b/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp
index 583dfbe7..07dd462 100644
--- a/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp
+++ b/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp
@@ -674,13 +674,8 @@
     ContentData* prevContent = nullptr;
     for (auto& item : toCSSValueList(*value)) {
         ContentData* nextContent = nullptr;
-        // TODO(timloh): This should just call styleImage to handle all the different image types
-        if (item->isImageGeneratorValue()) {
-            nextContent = ContentData::create(StyleGeneratedImage::create(toCSSImageGeneratorValue(*item)));
-        } else if (item->isImageSetValue()) {
-            nextContent = ContentData::create(state.elementStyleResources().setOrPendingFromValue(CSSPropertyContent, toCSSImageSetValue(*item)));
-        } else if (item->isImageValue()) {
-            nextContent = ContentData::create(state.elementStyleResources().cachedOrPendingFromValue(CSSPropertyContent, toCSSImageValue(*item)));
+        if (item->isImageGeneratorValue() || item->isImageSetValue() || item->isImageValue()) {
+            nextContent = ContentData::create(state.styleImage(CSSPropertyContent, *item));
         } else if (item->isCounterValue()) {
             CSSCounterValue* counterValue = toCSSCounterValue(item.get());
             EListStyleType listStyleType = NoneListStyle;
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index 8c475bbf..b4fde8e 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -3409,11 +3409,11 @@
     return true;
 }
 
-StyleSheetList* Document::styleSheets()
+StyleSheetList& Document::styleSheets()
 {
     if (!m_styleSheetList)
         m_styleSheetList = StyleSheetList::create(this);
-    return m_styleSheetList.get();
+    return *m_styleSheetList;
 }
 
 String Document::preferredStylesheetSet() const
@@ -5037,10 +5037,9 @@
     return getSecurityOrigin()->canAccess(other.get());
 }
 
-bool Document::allowInlineEventHandlers(Node* node, EventListener* listener, const String& contextURL, const WTF::OrdinalNumber& contextLine)
+bool Document::allowInlineEventHandler(Node* node, EventListener* listener, const String& contextURL, const WTF::OrdinalNumber& contextLine)
 {
-    bool allowedByHash = contentSecurityPolicy()->experimentalFeaturesEnabled() && contentSecurityPolicy()->allowScriptWithHash(listener->code());
-    if (!ContentSecurityPolicy::shouldBypassMainWorld(this) && !allowedByHash && !contentSecurityPolicy()->allowInlineEventHandlers(contextURL, contextLine))
+    if (!ContentSecurityPolicy::shouldBypassMainWorld(this) && !contentSecurityPolicy()->allowInlineEventHandler(listener->code(), contextURL, contextLine))
         return false;
 
     // HTML says that inline script needs browsing context to create its execution environment.
@@ -5052,7 +5051,7 @@
         return false;
     if (!frame->script().canExecuteScripts(NotAboutToExecuteScript))
         return false;
-    if (node && node->document() != this && !node->document().allowInlineEventHandlers(node, listener, contextURL, contextLine))
+    if (node && node->document() != this && !node->document().allowInlineEventHandler(node, listener, contextURL, contextLine))
         return false;
 
     return true;
diff --git a/third_party/WebKit/Source/core/dom/Document.h b/third_party/WebKit/Source/core/dom/Document.h
index 4a5afa0..e102c0b0 100644
--- a/third_party/WebKit/Source/core/dom/Document.h
+++ b/third_party/WebKit/Source/core/dom/Document.h
@@ -378,7 +378,7 @@
     bool isScriptExecutionReady() const { return isRenderingReady(); }
 
     // This is a DOM function.
-    StyleSheetList* styleSheets();
+    StyleSheetList& styleSheets();
 
     StyleEngine& styleEngine() { DCHECK(m_styleEngine.get()); return *m_styleEngine.get(); }
 
@@ -862,7 +862,7 @@
 
     bool isSecureTransitionTo(const KURL&) const;
 
-    bool allowInlineEventHandlers(Node*, EventListener*, const String& contextURL, const WTF::OrdinalNumber& contextLine);
+    bool allowInlineEventHandler(Node*, EventListener*, const String& contextURL, const WTF::OrdinalNumber& contextLine);
     bool allowExecutingScripts(Node*);
 
     void enforceSandboxFlags(SandboxFlags mask) override;
diff --git a/third_party/WebKit/Source/core/dom/DocumentOrShadowRoot.h b/third_party/WebKit/Source/core/dom/DocumentOrShadowRoot.h
index 1f4a04b..11fbf32 100644
--- a/third_party/WebKit/Source/core/dom/DocumentOrShadowRoot.h
+++ b/third_party/WebKit/Source/core/dom/DocumentOrShadowRoot.h
@@ -24,12 +24,12 @@
 
     static StyleSheetList* styleSheets(Document& document)
     {
-        return document.styleSheets();
+        return &document.styleSheets();
     }
 
     static StyleSheetList* styleSheets(ShadowRoot& shadowRoot)
     {
-        return shadowRoot.styleSheets();
+        return &shadowRoot.styleSheets();
     }
 
     static DOMSelection* getSelection(TreeScope& treeScope)
diff --git a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp
index ce1d001..2b19ef878 100644
--- a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp
+++ b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp
@@ -375,7 +375,7 @@
     const ContentSecurityPolicy* csp = elementDocument->contentSecurityPolicy();
     bool shouldBypassMainWorldCSP = (frame && frame->script().shouldBypassMainWorldCSP())
         || csp->allowScriptWithNonce(m_element->fastGetAttribute(HTMLNames::nonceAttr))
-        || csp->allowScriptWithHash(sourceCode.source().toString())
+        || csp->allowScriptWithHash(sourceCode.source().toString(), ContentSecurityPolicy::InlineType::Block)
         || (!isParserInserted() && csp->allowDynamic());
 
     if (!m_isExternalScript && (!shouldBypassMainWorldCSP && !csp->allowInlineScript(elementDocument->url(), m_startLineNumber, sourceCode.source().toString()))) {
diff --git a/third_party/WebKit/Source/core/dom/SelectorQuery.cpp b/third_party/WebKit/Source/core/dom/SelectorQuery.cpp
index 76151d5..5966fc9 100644
--- a/third_party/WebKit/Source/core/dom/SelectorQuery.cpp
+++ b/third_party/WebKit/Source/core/dom/SelectorQuery.cpp
@@ -205,10 +205,8 @@
 template <typename SelectorQueryTrait>
 void SelectorDataList::collectElementsByTagName(ContainerNode& rootNode, const QualifiedName& tagName,  typename SelectorQueryTrait::OutputType& output) const
 {
+    DCHECK_EQ(tagName.namespaceURI(), starAtom);
     for (Element& element : ElementTraversal::descendantsOf(rootNode)) {
-        // querySelector*() doesn't allow namespaces and throws before it gets
-        // here so we can ignore them.
-        DCHECK_EQ(tagName.namespaceURI(), starAtom);
         if (matchesTagName(tagName, element)) {
             SelectorQueryTrait::appendElement(output, element);
             if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
@@ -510,8 +508,15 @@
             collectElementsByClassName<SelectorQueryTrait>(rootNode, firstSelector.value(), output);
             return;
         case CSSSelector::Tag:
-            collectElementsByTagName<SelectorQueryTrait>(rootNode, firstSelector.tagQName(), output);
-            return;
+            if (firstSelector.tagQName().namespaceURI() == starAtom) {
+                collectElementsByTagName<SelectorQueryTrait>(rootNode, firstSelector.tagQName(), output);
+                return;
+            }
+            // querySelector*() doesn't allow namespace prefix resolution and
+            // throws before we get here, but we still may have selectors for
+            // elements without a namespace.
+            DCHECK_EQ(firstSelector.tagQName().namespaceURI(), nullAtom);
+            break;
         default:
             break; // If we need another fast path, add here.
         }
diff --git a/third_party/WebKit/Source/core/dom/StyleElement.cpp b/third_party/WebKit/Source/core/dom/StyleElement.cpp
index b10eff3..247c28a97 100644
--- a/third_party/WebKit/Source/core/dom/StyleElement.cpp
+++ b/third_party/WebKit/Source/core/dom/StyleElement.cpp
@@ -174,7 +174,7 @@
 
     const ContentSecurityPolicy* csp = document.contentSecurityPolicy();
     bool passesContentSecurityPolicyChecks = shouldBypassMainWorldCSP(e)
-        || csp->allowStyleWithHash(text)
+        || csp->allowStyleWithHash(text, ContentSecurityPolicy::InlineType::Block)
         || csp->allowStyleWithNonce(e->fastGetAttribute(HTMLNames::nonceAttr))
         || csp->allowInlineStyle(e->document().url(), m_startPosition.m_line, text);
 
diff --git a/third_party/WebKit/Source/core/dom/shadow/ElementShadow.cpp b/third_party/WebKit/Source/core/dom/shadow/ElementShadow.cpp
index 393a0ea..8823456 100644
--- a/third_party/WebKit/Source/core/dom/shadow/ElementShadow.cpp
+++ b/third_party/WebKit/Source/core/dom/shadow/ElementShadow.cpp
@@ -234,14 +234,14 @@
         if (!root || !otherRoot)
             return false;
 
-        StyleSheetList* list = root->styleSheets();
-        StyleSheetList* otherList = otherRoot->styleSheets();
+        StyleSheetList& list = root->styleSheets();
+        StyleSheetList& otherList = otherRoot->styleSheets();
 
-        if (list->length() != otherList->length())
+        if (list.length() != otherList.length())
             return false;
 
-        for (size_t i = 0; i < list->length(); i++) {
-            if (toCSSStyleSheet(list->item(i))->contents() != toCSSStyleSheet(otherList->item(i))->contents())
+        for (size_t i = 0; i < list.length(); i++) {
+            if (toCSSStyleSheet(list.item(i))->contents() != toCSSStyleSheet(otherList.item(i))->contents())
                 return false;
         }
         root = root->olderShadowRoot();
diff --git a/third_party/WebKit/Source/core/dom/shadow/ShadowRoot.cpp b/third_party/WebKit/Source/core/dom/shadow/ShadowRoot.cpp
index 078e1fa..c7d7c0d 100644
--- a/third_party/WebKit/Source/core/dom/shadow/ShadowRoot.cpp
+++ b/third_party/WebKit/Source/core/dom/shadow/ShadowRoot.cpp
@@ -35,10 +35,11 @@
 #include "core/dom/Text.h"
 #include "core/dom/shadow/ElementShadow.h"
 #include "core/dom/shadow/InsertionPoint.h"
-#include "core/dom/shadow/ShadowRootRareData.h"
 #include "core/dom/shadow/ShadowRootRareDataV0.h"
+#include "core/dom/shadow/SlotAssignment.h"
 #include "core/editing/serializers/Serialization.h"
 #include "core/html/HTMLShadowElement.h"
+#include "core/html/HTMLSlotElement.h"
 #include "public/platform/Platform.h"
 
 namespace blink {
@@ -55,6 +56,7 @@
     : DocumentFragment(0, CreateShadowRoot)
     , TreeScope(*this, document)
     , m_numberOfStyles(0)
+    , m_childShadowRootCount(0)
     , m_type(static_cast<unsigned>(type))
     , m_registeredWithParentShadowRoot(false)
     , m_descendantInsertionPointsIsValid(false)
@@ -102,6 +104,19 @@
     ensureShadowRootRareDataV0().setOlderShadowRoot(root);
 }
 
+SlotAssignment& ShadowRoot::ensureSlotAssignment()
+{
+    if (!m_slotAssignment)
+        m_slotAssignment = SlotAssignment::create();
+    return *m_slotAssignment;
+}
+
+HTMLSlotElement* ShadowRoot::assignedSlotFor(const Node& node) const
+{
+    DCHECK(m_slotAssignment);
+    return m_slotAssignment->assignedSlotFor(node);
+}
+
 Node* ShadowRoot::cloneNode(bool, ExceptionState& exceptionState)
 {
     exceptionState.throwDOMException(NotSupportedError, "ShadowRoot nodes are not clonable.");
@@ -209,15 +224,6 @@
     --m_numberOfStyles;
 }
 
-ShadowRootRareData& ShadowRoot::ensureShadowRootRareData()
-{
-    if (m_shadowRootRareData)
-        return *m_shadowRootRareData;
-
-    m_shadowRootRareData = new ShadowRootRareData;
-    return *m_shadowRootRareData;
-}
-
 ShadowRootRareDataV0& ShadowRoot::ensureShadowRootRareDataV0()
 {
     if (m_shadowRootRareDataV0)
@@ -237,11 +243,6 @@
     return m_shadowRootRareDataV0 ? m_shadowRootRareDataV0->containsContentElements() : false;
 }
 
-bool ShadowRoot::containsShadowRoots() const
-{
-    return m_shadowRootRareData ? m_shadowRootRareData->containsShadowRoots() : false;
-}
-
 unsigned ShadowRoot::descendantShadowElementCount() const
 {
     return m_shadowRootRareDataV0 ? m_shadowRootRareDataV0->descendantShadowElementCount() : 0;
@@ -271,24 +272,6 @@
     invalidateDescendantInsertionPoints();
 }
 
-void ShadowRoot::addChildShadowRoot()
-{
-    ensureShadowRootRareData().didAddChildShadowRoot();
-}
-
-void ShadowRoot::removeChildShadowRoot()
-{
-    // FIXME: Why isn't this an ASSERT?
-    if (!m_shadowRootRareData)
-        return;
-    m_shadowRootRareData->didRemoveChildShadowRoot();
-}
-
-unsigned ShadowRoot::childShadowRootCount() const
-{
-    return m_shadowRootRareData ? m_shadowRootRareData->childShadowRootCount() : 0;
-}
-
 void ShadowRoot::invalidateDescendantInsertionPoints()
 {
     m_descendantInsertionPointsIsValid = false;
@@ -315,56 +298,56 @@
     return m_shadowRootRareDataV0->descendantInsertionPoints();
 }
 
-StyleSheetList* ShadowRoot::styleSheets()
+StyleSheetList& ShadowRoot::styleSheets()
 {
-    if (!ensureShadowRootRareData().styleSheets())
-        m_shadowRootRareData->setStyleSheets(StyleSheetList::create(this));
-
-    return m_shadowRootRareData->styleSheets();
+    if (!m_styleSheetList)
+        setStyleSheets(StyleSheetList::create(this));
+    return *m_styleSheetList;
 }
 
 void ShadowRoot::didAddSlot()
 {
-    ensureShadowRootRareData().didAddSlot();
+    ensureSlotAssignment().didAddSlot();
     invalidateDescendantSlots();
 }
 
 void ShadowRoot::didRemoveSlot()
 {
-    DCHECK(m_shadowRootRareData);
-    m_shadowRootRareData->didRemoveSlot();
+    DCHECK(m_slotAssignment);
+    m_slotAssignment->didRemoveSlot();
     invalidateDescendantSlots();
 }
 
 void ShadowRoot::invalidateDescendantSlots()
 {
+    DCHECK(m_slotAssignment);
     m_descendantSlotsIsValid = false;
-    m_shadowRootRareData->clearDescendantSlots();
+    m_slotAssignment->clearDescendantSlots();
 }
 
 unsigned ShadowRoot::descendantSlotCount() const
 {
-    return m_shadowRootRareData ? m_shadowRootRareData->descendantSlotCount() : 0;
+    return m_slotAssignment ? m_slotAssignment->descendantSlotCount() : 0;
 }
 
 const HeapVector<Member<HTMLSlotElement>>& ShadowRoot::descendantSlots()
 {
     DEFINE_STATIC_LOCAL(HeapVector<Member<HTMLSlotElement>>, emptyList, (new HeapVector<Member<HTMLSlotElement>>));
     if (m_descendantSlotsIsValid) {
-        DCHECK(m_shadowRootRareData);
-        return m_shadowRootRareData->descendantSlots();
+        DCHECK(m_slotAssignment);
+        return m_slotAssignment->descendantSlots();
     }
     if (descendantSlotCount() == 0)
         return emptyList;
 
-    DCHECK(m_shadowRootRareData);
+    DCHECK(m_slotAssignment);
     HeapVector<Member<HTMLSlotElement>> slots;
     slots.reserveCapacity(descendantSlotCount());
     for (HTMLSlotElement& slot : Traversal<HTMLSlotElement>::descendantsOf(rootNode()))
         slots.append(&slot);
-    m_shadowRootRareData->setDescendantSlots(slots);
+    m_slotAssignment->setDescendantSlots(slots);
     m_descendantSlotsIsValid = true;
-    return m_shadowRootRareData->descendantSlots();
+    return m_slotAssignment->descendantSlots();
 }
 
 void ShadowRoot::assignV1()
@@ -383,9 +366,9 @@
 
 DEFINE_TRACE(ShadowRoot)
 {
-    visitor->trace(m_shadowRootRareData);
     visitor->trace(m_shadowRootRareDataV0);
     visitor->trace(m_slotAssignment);
+    visitor->trace(m_styleSheetList);
     TreeScope::trace(visitor);
     DocumentFragment::trace(visitor);
 }
diff --git a/third_party/WebKit/Source/core/dom/shadow/ShadowRoot.h b/third_party/WebKit/Source/core/dom/shadow/ShadowRoot.h
index 8000de5..944a022 100644
--- a/third_party/WebKit/Source/core/dom/shadow/ShadowRoot.h
+++ b/third_party/WebKit/Source/core/dom/shadow/ShadowRoot.h
@@ -32,7 +32,6 @@
 #include "core/dom/DocumentFragment.h"
 #include "core/dom/Element.h"
 #include "core/dom/TreeScope.h"
-#include "core/dom/shadow/SlotAssignment.h"
 
 namespace blink {
 
@@ -40,9 +39,10 @@
 class ElementShadow;
 class ExceptionState;
 class HTMLShadowElement;
+class HTMLSlotElement;
 class InsertionPoint;
-class ShadowRootRareData;
 class ShadowRootRareDataV0;
+class SlotAssignment;
 class StyleSheetList;
 
 enum class ShadowRootType {
@@ -64,60 +64,57 @@
         return new ShadowRoot(document, type);
     }
 
-    void recalcStyle(StyleRecalcChange);
-
     // Disambiguate between Node and TreeScope hierarchies; TreeScope's implementation is simpler.
     using TreeScope::document;
     using TreeScope::getElementById;
 
+    // Make protected methods from base class public here.
+    using TreeScope::setDocument;
+    using TreeScope::setParentTreeScope;
+
     // TODO(kochi): crbug.com/507413 In non-Oilpan, host() may return null during queued
     // event handling (e.g. during execCommand()).
     Element* host() const { return toElement(parentOrShadowHostNode()); }
     ElementShadow* owner() const { return host() ? host()->shadow() : 0; }
-
-    ShadowRoot* youngerShadowRoot() const;
-    ShadowRoot* olderShadowRoot() const;
-    ShadowRoot* olderShadowRootForBindings() const;
-
-    void setYoungerShadowRoot(ShadowRoot&);
-    void setOlderShadowRoot(ShadowRoot&);
-
+    ShadowRootType type() const { return static_cast<ShadowRootType>(m_type); }
     String mode() const { return (type() == ShadowRootType::V0 || type() == ShadowRootType::Open) ? "open" : "closed"; };
 
     bool isOpenOrV0() const { return type() == ShadowRootType::V0 || type() == ShadowRootType::Open; }
-
     bool isV1() const { return type() == ShadowRootType::Open || type() == ShadowRootType::Closed; }
 
-    bool isYoungest() const { return !youngerShadowRoot(); }
-    bool isOldest() const { return !olderShadowRoot(); }
-
     void attach(const AttachContext& = AttachContext()) override;
 
     InsertionNotificationRequest insertedInto(ContainerNode*) override;
     void removedFrom(ContainerNode*) override;
 
-    void registerScopedHTMLStyleChild();
-    void unregisterScopedHTMLStyleChild();
-
+    // For V0
+    ShadowRoot* youngerShadowRoot() const;
+    ShadowRoot* olderShadowRoot() const;
+    ShadowRoot* olderShadowRootForBindings() const;
+    void setYoungerShadowRoot(ShadowRoot&);
+    void setOlderShadowRoot(ShadowRoot&);
+    bool isYoungest() const { return !youngerShadowRoot(); }
+    bool isOldest() const { return !olderShadowRoot(); }
     bool containsShadowElements() const;
     bool containsContentElements() const;
     bool containsInsertionPoints() const { return containsShadowElements() || containsContentElements(); }
-    bool containsShadowRoots() const;
-
     unsigned descendantShadowElementCount() const;
-
-    // For Internals, don't use this.
-    unsigned childShadowRootCount() const;
-    unsigned numberOfStyles() const { return m_numberOfStyles; }
-
     HTMLShadowElement* shadowInsertionPointOfYoungerShadowRoot() const;
     void setShadowInsertionPointOfYoungerShadowRoot(HTMLShadowElement*);
-
     void didAddInsertionPoint(InsertionPoint*);
     void didRemoveInsertionPoint(InsertionPoint*);
     const HeapVector<Member<InsertionPoint>>& descendantInsertionPoints();
 
-    ShadowRootType type() const { return static_cast<ShadowRootType>(m_type); }
+    // For Internals, don't use this.
+    unsigned childShadowRootCount() const { return m_childShadowRootCount; }
+    unsigned numberOfStyles() const { return m_numberOfStyles; }
+
+    void recalcStyle(StyleRecalcChange);
+
+    void registerScopedHTMLStyleChild();
+    void unregisterScopedHTMLStyleChild();
+
+    SlotAssignment& ensureSlotAssignment();
 
     void didAddSlot();
     void didRemoveSlot();
@@ -126,15 +123,7 @@
     void assignV1();
     void distributeV1();
 
-    HTMLSlotElement* assignedSlotFor(const Node& node) const
-    {
-        DCHECK(m_slotAssignment);
-        return m_slotAssignment->assignedSlotFor(node);
-    }
-
-    // Make protected methods from base class public here.
-    using TreeScope::setDocument;
-    using TreeScope::setParentTreeScope;
+    HTMLSlotElement* assignedSlotFor(const Node&) const;
 
     Element* activeElement() const;
 
@@ -143,11 +132,14 @@
 
     Node* cloneNode(bool, ExceptionState&);
 
-    StyleSheetList* styleSheets();
-
     void setDelegatesFocus(bool flag) { m_delegatesFocus = flag; }
     bool delegatesFocus() const { return m_delegatesFocus; }
 
+    bool containsShadowRoots() const { return m_childShadowRootCount; }
+
+    StyleSheetList& styleSheets();
+    void setStyleSheets(StyleSheetList* styleSheetList) { m_styleSheetList = styleSheetList; }
+
     DECLARE_VIRTUAL_TRACE();
 
 private:
@@ -156,11 +148,10 @@
 
     void childrenChanged(const ChildrenChange&) override;
 
-    ShadowRootRareData& ensureShadowRootRareData();
     ShadowRootRareDataV0& ensureShadowRootRareDataV0();
 
-    void addChildShadowRoot();
-    void removeChildShadowRoot();
+    void addChildShadowRoot() { ++m_childShadowRootCount; }
+    void removeChildShadowRoot() { DCHECK_GT(m_childShadowRootCount, 0u); --m_childShadowRootCount; }
     void invalidateDescendantInsertionPoints();
 
     // ShadowRoots should never be cloned.
@@ -172,10 +163,11 @@
     void invalidateDescendantSlots();
     unsigned descendantSlotCount() const;
 
-    Member<ShadowRootRareData> m_shadowRootRareData;
     Member<ShadowRootRareDataV0> m_shadowRootRareDataV0;
+    Member<StyleSheetList> m_styleSheetList;
     Member<SlotAssignment> m_slotAssignment;
-    unsigned m_numberOfStyles : 26;
+    unsigned m_numberOfStyles : 13;
+    unsigned m_childShadowRootCount : 13;
     unsigned m_type : 2;
     unsigned m_registeredWithParentShadowRoot : 1;
     unsigned m_descendantInsertionPointsIsValid : 1;
diff --git a/third_party/WebKit/Source/core/dom/shadow/ShadowRootRareData.h b/third_party/WebKit/Source/core/dom/shadow/ShadowRootRareData.h
deleted file mode 100644
index 9c5d91b..0000000
--- a/third_party/WebKit/Source/core/dom/shadow/ShadowRootRareData.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef ShadowRootRareData_h
-#define ShadowRootRareData_h
-
-#include "core/dom/shadow/InsertionPoint.h"
-#include "core/html/HTMLSlotElement.h"
-#include "wtf/Vector.h"
-
-namespace blink {
-
-class ShadowRootRareData : public GarbageCollected<ShadowRootRareData> {
-public:
-    ShadowRootRareData()
-        : m_childShadowRootCount(0)
-        , m_descendantSlotCount(0)
-    {
-    }
-
-    bool containsShadowRoots() const { return m_childShadowRootCount; }
-
-    void didAddChildShadowRoot() { ++m_childShadowRootCount; }
-    void didRemoveChildShadowRoot() { DCHECK_GT(m_childShadowRootCount, 0u); --m_childShadowRootCount; }
-
-    unsigned childShadowRootCount() const { return m_childShadowRootCount; }
-
-    StyleSheetList* styleSheets() { return m_styleSheetList.get(); }
-    void setStyleSheets(StyleSheetList* styleSheetList) { m_styleSheetList = styleSheetList; }
-
-    void didAddSlot() { ++m_descendantSlotCount; }
-    void didRemoveSlot() { DCHECK_GT(m_descendantSlotCount, 0u); --m_descendantSlotCount; }
-
-    unsigned descendantSlotCount() const { return m_descendantSlotCount; }
-
-    const HeapVector<Member<HTMLSlotElement>>& descendantSlots() const { return m_descendantSlots; }
-
-    void setDescendantSlots(HeapVector<Member<HTMLSlotElement>>& slots) { m_descendantSlots.swap(slots); }
-    void clearDescendantSlots() { m_descendantSlots.clear(); }
-
-    DEFINE_INLINE_TRACE()
-    {
-        visitor->trace(m_styleSheetList);
-        visitor->trace(m_descendantSlots);
-    }
-
-private:
-    unsigned m_childShadowRootCount;
-    Member<StyleSheetList> m_styleSheetList;
-    unsigned m_descendantSlotCount;
-    HeapVector<Member<HTMLSlotElement>> m_descendantSlots;
-};
-
-} // namespace blink
-
-#endif
diff --git a/third_party/WebKit/Source/core/dom/shadow/SlotAssignment.cpp b/third_party/WebKit/Source/core/dom/shadow/SlotAssignment.cpp
index 44274a2..a13e9fb 100644
--- a/third_party/WebKit/Source/core/dom/shadow/SlotAssignment.cpp
+++ b/third_party/WebKit/Source/core/dom/shadow/SlotAssignment.cpp
@@ -107,6 +107,7 @@
 
 DEFINE_TRACE(SlotAssignment)
 {
+    visitor->trace(m_descendantSlots);
     visitor->trace(m_assignment);
 }
 
diff --git a/third_party/WebKit/Source/core/dom/shadow/SlotAssignment.h b/third_party/WebKit/Source/core/dom/shadow/SlotAssignment.h
index 4ed964673..50c5b48 100644
--- a/third_party/WebKit/Source/core/dom/shadow/SlotAssignment.h
+++ b/third_party/WebKit/Source/core/dom/shadow/SlotAssignment.h
@@ -24,13 +24,25 @@
     void resolveAssignment(ShadowRoot&);
     void resolveDistribution(ShadowRoot&);
 
+    void didAddSlot() { ++m_descendantSlotCount; }
+    void didRemoveSlot() { DCHECK_GT(m_descendantSlotCount, 0u); --m_descendantSlotCount; }
+    unsigned descendantSlotCount() const { return m_descendantSlotCount; }
+
+    const HeapVector<Member<HTMLSlotElement>>& descendantSlots() const { return m_descendantSlots; }
+
+    void setDescendantSlots(HeapVector<Member<HTMLSlotElement>>& slots) { m_descendantSlots.swap(slots); }
+    void clearDescendantSlots() { m_descendantSlots.clear(); }
+
     DECLARE_TRACE();
 
 private:
-    SlotAssignment() { }
+    SlotAssignment() { };
 
     void assign(Node&, HTMLSlotElement&);
     void distribute(Node&, HTMLSlotElement&);
+
+    unsigned m_descendantSlotCount = 0;
+    HeapVector<Member<HTMLSlotElement>> m_descendantSlots;
     HeapHashMap<Member<Node>, Member<HTMLSlotElement>> m_assignment;
 };
 
diff --git a/third_party/WebKit/Source/core/editing/VisibleUnits.cpp b/third_party/WebKit/Source/core/editing/VisibleUnits.cpp
index 9adde60..239873a 100644
--- a/third_party/WebKit/Source/core/editing/VisibleUnits.cpp
+++ b/third_party/WebKit/Source/core/editing/VisibleUnits.cpp
@@ -671,23 +671,20 @@
     const PositionTemplate<Strategy> end = pos.parentAnchoredEquivalent();
 
     ForwardsTextBuffer suffixString;
-    unsigned suffixLength = 0;
-
     if (requiresContextForWordBoundary(characterBefore(c))) {
         TextIteratorAlgorithm<Strategy> forwardsIterator(end, PositionTemplate<Strategy>::afterNode(boundary));
         while (!forwardsIterator.atEnd()) {
-            // TODO(xiaochengh): Eliminate this intermediate buffer.
-            ForwardsTextBuffer characters;
-            forwardsIterator.copyTextTo(&characters);
-            int i = endOfFirstWordBoundaryContext(characters.data(), characters.size());
-            suffixString.pushRange(characters.data(), i);
-            suffixLength += i;
-            if (static_cast<unsigned>(i) < characters.size())
+            forwardsIterator.copyTextTo(&suffixString);
+            int contextEndIndex = endOfFirstWordBoundaryContext(suffixString.data() + suffixString.size() - forwardsIterator.length(), forwardsIterator.length());
+            if (contextEndIndex < forwardsIterator.length()) {
+                suffixString.shrink(forwardsIterator.length() - contextEndIndex);
                 break;
+            }
             forwardsIterator.advance();
         }
     }
 
+    unsigned suffixLength = suffixString.size();
     BackwardsTextBuffer string;
     string.pushRange(suffixString.data(), suffixString.size());
 
@@ -759,24 +756,20 @@
     const PositionTemplate<Strategy> start(pos.parentAnchoredEquivalent());
 
     BackwardsTextBuffer prefixString;
-    unsigned prefixLength = 0;
-
     if (requiresContextForWordBoundary(characterAfter(c))) {
         SimplifiedBackwardsTextIteratorAlgorithm<Strategy> backwardsIterator(PositionTemplate<Strategy>::firstPositionInNode(&d), start);
         while (!backwardsIterator.atEnd()) {
-            // TODO(xiaochengh): Eliminate this intermediate buffer.
-            BackwardsTextBuffer characters;
-            backwardsIterator.copyTextTo(&characters);
-            int length = characters.size();
-            int i = startOfLastWordBoundaryContext(characters.data(), length);
-            prefixString.pushRange(characters.data() + i, length - i);
-            prefixLength += length - i;
-            if (i > 0)
+            backwardsIterator.copyTextTo(&prefixString);
+            int contextStartIndex = startOfLastWordBoundaryContext(prefixString.data(), backwardsIterator.length());
+            if (contextStartIndex > 0) {
+                prefixString.shrink(contextStartIndex);
                 break;
+            }
             backwardsIterator.advance();
         }
     }
 
+    unsigned prefixLength = prefixString.size();
     ForwardsTextBuffer string;
     string.pushRange(prefixString.data(), prefixString.size());
 
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextBufferBase.h b/third_party/WebKit/Source/core/editing/iterators/TextBufferBase.h
index 95a0624..b7a5b839 100644
--- a/third_party/WebKit/Source/core/editing/iterators/TextBufferBase.h
+++ b/third_party/WebKit/Source/core/editing/iterators/TextBufferBase.h
@@ -32,6 +32,8 @@
         std::copy(other, other + length, ensureDestination(length));
     }
 
+    void shrink(size_t delta) { DCHECK_LE(delta, m_size); m_size -= delta; }
+
 protected:
     TextBufferBase();
     UChar* ensureDestination(size_t length);
diff --git a/third_party/WebKit/Source/core/events/CompositionEvent.cpp b/third_party/WebKit/Source/core/events/CompositionEvent.cpp
index 9544626..d5ca38b 100644
--- a/third_party/WebKit/Source/core/events/CompositionEvent.cpp
+++ b/third_party/WebKit/Source/core/events/CompositionEvent.cpp
@@ -51,7 +51,7 @@
 
 void CompositionEvent::initCompositionEvent(const AtomicString& type, bool canBubble, bool cancelable, AbstractView* view, const String& data)
 {
-    if (dispatched())
+    if (isBeingDispatched())
         return;
 
     initUIEvent(type, canBubble, cancelable, view, 0);
diff --git a/third_party/WebKit/Source/core/events/CustomEvent.cpp b/third_party/WebKit/Source/core/events/CustomEvent.cpp
index 4c66fd2..ed23900 100644
--- a/third_party/WebKit/Source/core/events/CustomEvent.cpp
+++ b/third_party/WebKit/Source/core/events/CustomEvent.cpp
@@ -50,7 +50,7 @@
 
 void CustomEvent::initCustomEvent(const AtomicString& type, bool canBubble, bool cancelable, PassRefPtr<SerializedScriptValue> serializedDetail)
 {
-    if (dispatched())
+    if (isBeingDispatched())
         return;
 
     initEvent(type, canBubble, cancelable);
diff --git a/third_party/WebKit/Source/core/events/Event.cpp b/third_party/WebKit/Source/core/events/Event.cpp
index fcbe35e..0971daa 100644
--- a/third_party/WebKit/Source/core/events/Event.cpp
+++ b/third_party/WebKit/Source/core/events/Event.cpp
@@ -114,7 +114,7 @@
 
 void Event::initEvent(const AtomicString& eventTypeArg, bool canBubbleArg, bool cancelableArg, EventTarget* relatedTarget)
 {
-    if (dispatched())
+    if (isBeingDispatched())
         return;
 
     m_propagationStopped = false;
diff --git a/third_party/WebKit/Source/core/events/Event.h b/third_party/WebKit/Source/core/events/Event.h
index 505c055..4d436246 100644
--- a/third_party/WebKit/Source/core/events/Event.h
+++ b/third_party/WebKit/Source/core/events/Event.h
@@ -216,7 +216,6 @@
     Event(const AtomicString& type, const EventInit&);
 
     virtual void receivedTarget();
-    bool dispatched() const { return m_target; }
 
     void setCanBubble(bool bubble) { m_canBubble = bubble; }
 
diff --git a/third_party/WebKit/Source/core/events/KeyboardEvent.cpp b/third_party/WebKit/Source/core/events/KeyboardEvent.cpp
index 185341f..146800f 100644
--- a/third_party/WebKit/Source/core/events/KeyboardEvent.cpp
+++ b/third_party/WebKit/Source/core/events/KeyboardEvent.cpp
@@ -113,7 +113,7 @@
 void KeyboardEvent::initKeyboardEvent(ScriptState* scriptState, const AtomicString& type, bool canBubble, bool cancelable, AbstractView* view,
     const String& keyIdentifier, unsigned location, bool ctrlKey, bool altKey, bool shiftKey, bool metaKey)
 {
-    if (dispatched())
+    if (isBeingDispatched())
         return;
 
     if (scriptState->world().isIsolatedWorld())
diff --git a/third_party/WebKit/Source/core/events/MessageEvent.cpp b/third_party/WebKit/Source/core/events/MessageEvent.cpp
index 6c676b67..33bb457 100644
--- a/third_party/WebKit/Source/core/events/MessageEvent.cpp
+++ b/third_party/WebKit/Source/core/events/MessageEvent.cpp
@@ -140,7 +140,7 @@
 
 void MessageEvent::initMessageEvent(const AtomicString& type, bool canBubble, bool cancelable, ScriptValue data, const String& origin, const String& lastEventId, DOMWindow* source, MessagePortArray* ports)
 {
-    if (dispatched())
+    if (isBeingDispatched())
         return;
 
     initEvent(type, canBubble, cancelable);
@@ -156,7 +156,7 @@
 
 void MessageEvent::initMessageEvent(const AtomicString& type, bool canBubble, bool cancelable, PassRefPtr<SerializedScriptValue> data, const String& origin, const String& lastEventId, DOMWindow* source, MessagePortArray* ports)
 {
-    if (dispatched())
+    if (isBeingDispatched())
         return;
 
     initEvent(type, canBubble, cancelable);
diff --git a/third_party/WebKit/Source/core/events/MouseEvent.cpp b/third_party/WebKit/Source/core/events/MouseEvent.cpp
index f4dfdc6..ecd784f3 100644
--- a/third_party/WebKit/Source/core/events/MouseEvent.cpp
+++ b/third_party/WebKit/Source/core/events/MouseEvent.cpp
@@ -181,7 +181,7 @@
                                 bool ctrlKey, bool altKey, bool shiftKey, bool metaKey,
                                 short button, EventTarget* relatedTarget, unsigned short buttons)
 {
-    if (dispatched())
+    if (isBeingDispatched())
         return;
 
     if (scriptState && scriptState->world().isIsolatedWorld())
diff --git a/third_party/WebKit/Source/core/events/MutationEvent.cpp b/third_party/WebKit/Source/core/events/MutationEvent.cpp
index 1a9b917..065e9c0 100644
--- a/third_party/WebKit/Source/core/events/MutationEvent.cpp
+++ b/third_party/WebKit/Source/core/events/MutationEvent.cpp
@@ -49,7 +49,7 @@
                                       const String& prevValue, const String& newValue,
                                       const String& attrName, unsigned short attrChange)
 {
-    if (dispatched())
+    if (isBeingDispatched())
         return;
 
     initEvent(type, canBubble, cancelable);
diff --git a/third_party/WebKit/Source/core/events/TextEvent.cpp b/third_party/WebKit/Source/core/events/TextEvent.cpp
index 0cca759d..65ff7dc 100644
--- a/third_party/WebKit/Source/core/events/TextEvent.cpp
+++ b/third_party/WebKit/Source/core/events/TextEvent.cpp
@@ -89,7 +89,7 @@
 
 void TextEvent::initTextEvent(const AtomicString& type, bool canBubble, bool cancelable, AbstractView* view, const String& data)
 {
-    if (dispatched())
+    if (isBeingDispatched())
         return;
 
     initUIEvent(type, canBubble, cancelable, view, 0);
diff --git a/third_party/WebKit/Source/core/events/TouchEvent.cpp b/third_party/WebKit/Source/core/events/TouchEvent.cpp
index 085c275c..721ec81 100644
--- a/third_party/WebKit/Source/core/events/TouchEvent.cpp
+++ b/third_party/WebKit/Source/core/events/TouchEvent.cpp
@@ -68,7 +68,7 @@
     int, int, int, int,
     bool ctrlKey, bool altKey, bool shiftKey, bool metaKey)
 {
-    if (dispatched())
+    if (isBeingDispatched())
         return;
 
     if (scriptState->world().isIsolatedWorld())
diff --git a/third_party/WebKit/Source/core/events/UIEvent.cpp b/third_party/WebKit/Source/core/events/UIEvent.cpp
index 5194710..317cf06 100644
--- a/third_party/WebKit/Source/core/events/UIEvent.cpp
+++ b/third_party/WebKit/Source/core/events/UIEvent.cpp
@@ -83,7 +83,7 @@
 
 void UIEvent::initUIEventInternal(const AtomicString& typeArg, bool canBubbleArg, bool cancelableArg, EventTarget* relatedTarget, AbstractView* viewArg, int detailArg, InputDeviceCapabilities* sourceCapabilitiesArg)
 {
-    if (dispatched())
+    if (isBeingDispatched())
         return;
 
     initEvent(typeArg, canBubbleArg, cancelableArg, relatedTarget);
diff --git a/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp b/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp
index 8f74b66..fe57589 100644
--- a/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp
+++ b/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp
@@ -130,6 +130,11 @@
     return !directive || directive->allowHash(hashValue);
 }
 
+bool CSPDirectiveList::checkHashedAttributes(SourceListDirective* directive) const
+{
+    return !directive || directive->allowHashedAttributes();
+}
+
 bool CSPDirectiveList::checkDynamic(SourceListDirective* directive) const
 {
     return !directive || directive->allowDynamic();
@@ -423,13 +428,21 @@
     return checkNonce(operativeDirective(m_styleSrc.get()), nonce);
 }
 
-bool CSPDirectiveList::allowScriptHash(const CSPHashValue& hashValue) const
+bool CSPDirectiveList::allowScriptHash(const CSPHashValue& hashValue, ContentSecurityPolicy::InlineType type) const
 {
+    if (type == ContentSecurityPolicy::InlineType::Attribute) {
+        if (!m_policy->experimentalFeaturesEnabled())
+            return false;
+        if (!checkHashedAttributes(operativeDirective(m_scriptSrc.get())))
+            return false;
+    }
     return checkHash(operativeDirective(m_scriptSrc.get()), hashValue);
 }
 
-bool CSPDirectiveList::allowStyleHash(const CSPHashValue& hashValue) const
+bool CSPDirectiveList::allowStyleHash(const CSPHashValue& hashValue, ContentSecurityPolicy::InlineType type) const
 {
+    if (type != ContentSecurityPolicy::InlineType::Block)
+        return false;
     return checkHash(operativeDirective(m_styleSrc.get()), hashValue);
 }
 
diff --git a/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.h b/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.h
index 066c622..0f1ded5 100644
--- a/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.h
+++ b/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.h
@@ -61,8 +61,8 @@
     bool allowAncestors(LocalFrame*, const KURL&, ContentSecurityPolicy::ReportingStatus) const;
     bool allowScriptNonce(const String&) const;
     bool allowStyleNonce(const String&) const;
-    bool allowScriptHash(const CSPHashValue&) const;
-    bool allowStyleHash(const CSPHashValue&) const;
+    bool allowScriptHash(const CSPHashValue&, ContentSecurityPolicy::InlineType) const;
+    bool allowStyleHash(const CSPHashValue&, ContentSecurityPolicy::InlineType) const;
     bool allowDynamic() const;
 
     const String& evalDisabledErrorMessage() const { return m_evalDisabledErrorMessage; }
@@ -111,6 +111,7 @@
     bool checkDynamic(SourceListDirective*) const;
     bool checkNonce(SourceListDirective*, const String&) const;
     bool checkHash(SourceListDirective*, const CSPHashValue&) const;
+    bool checkHashedAttributes(SourceListDirective*) const;
     bool checkSource(SourceListDirective*, const KURL&, ContentSecurityPolicy::RedirectStatus) const;
     bool checkMediaType(MediaListDirective*, const String& type, const String& typeAttribute) const;
     bool checkAncestors(SourceListDirective*, LocalFrame*) const;
diff --git a/third_party/WebKit/Source/core/frame/csp/CSPSourceList.cpp b/third_party/WebKit/Source/core/frame/csp/CSPSourceList.cpp
index 42d4c08..f9915535 100644
--- a/third_party/WebKit/Source/core/frame/csp/CSPSourceList.cpp
+++ b/third_party/WebKit/Source/core/frame/csp/CSPSourceList.cpp
@@ -39,6 +39,7 @@
     , m_allowInline(false)
     , m_allowEval(false)
     , m_allowDynamic(false)
+    , m_allowHashedAttributes(false)
     , m_hashAlgorithmsUsed(0)
 {
 }
@@ -89,6 +90,11 @@
     return m_hashes.contains(hashValue);
 }
 
+bool CSPSourceList::allowHashedAttributes() const
+{
+    return m_allowHashedAttributes;
+}
+
 uint8_t CSPSourceList::hashAlgorithmsUsed() const
 {
     return m_hashAlgorithmsUsed;
@@ -175,6 +181,11 @@
         return true;
     }
 
+    if (equalIgnoringCase("'unsafe-hashed-attributes'", begin, end - begin)) {
+        addSourceUnsafeHashedAttributes();
+        return true;
+    }
+
     String nonce;
     if (!parseNonce(begin, end, nonce))
         return false;
@@ -497,6 +508,11 @@
     m_allowDynamic = true;
 }
 
+void CSPSourceList::addSourceUnsafeHashedAttributes()
+{
+    m_allowHashedAttributes = true;
+}
+
 void CSPSourceList::addSourceNonce(const String& nonce)
 {
     m_nonces.add(nonce);
diff --git a/third_party/WebKit/Source/core/frame/csp/CSPSourceList.h b/third_party/WebKit/Source/core/frame/csp/CSPSourceList.h
index 4850102..9dd3117 100644
--- a/third_party/WebKit/Source/core/frame/csp/CSPSourceList.h
+++ b/third_party/WebKit/Source/core/frame/csp/CSPSourceList.h
@@ -33,6 +33,7 @@
     bool allowDynamic() const;
     bool allowNonce(const String&) const;
     bool allowHash(const CSPHashValue&) const;
+    bool allowHashedAttributes() const;
     uint8_t hashAlgorithmsUsed() const;
 
     bool isHashOrNoncePresent() const;
@@ -51,6 +52,7 @@
     void addSourceUnsafeInline();
     void addSourceUnsafeEval();
     void addSourceUnsafeDynamic();
+    void addSourceUnsafeHashedAttributes();
     void addSourceNonce(const String& nonce);
     void addSourceHash(const ContentSecurityPolicyHashAlgorithm&, const DigestValue& hash);
 
@@ -64,6 +66,7 @@
     bool m_allowInline;
     bool m_allowEval;
     bool m_allowDynamic;
+    bool m_allowHashedAttributes;
     HashSet<String> m_nonces;
     HashSet<CSPHashValue> m_hashes;
     uint8_t m_hashAlgorithmsUsed;
diff --git a/third_party/WebKit/Source/core/frame/csp/CSPSourceListTest.cpp b/third_party/WebKit/Source/core/frame/csp/CSPSourceListTest.cpp
index 91405a7..df588a0 100644
--- a/third_party/WebKit/Source/core/frame/csp/CSPSourceListTest.cpp
+++ b/third_party/WebKit/Source/core/frame/csp/CSPSourceListTest.cpp
@@ -62,6 +62,16 @@
     EXPECT_TRUE(sourceList.allowDynamic());
 }
 
+TEST_F(CSPSourceListTest, BasicMatchingUnsafeHashedAttributes)
+{
+    String sources = "'unsafe-hashed-attributes'";
+    CSPSourceList sourceList(csp.get(), "script-src");
+    parseSourceList(sourceList, sources);
+
+    EXPECT_TRUE(sourceList.allowHashedAttributes());
+}
+
+
 TEST_F(CSPSourceListTest, BasicMatchingStar)
 {
     KURL base;
diff --git a/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.cpp b/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.cpp
index f3d35c4..950512fc 100644
--- a/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.cpp
+++ b/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.cpp
@@ -372,11 +372,11 @@
     return true;
 }
 
-template<bool (CSPDirectiveList::*allowed)(const CSPHashValue&) const>
-bool isAllowedByAllWithHash(const CSPDirectiveListVector& policies, const CSPHashValue& hashValue)
+template<bool (CSPDirectiveList::*allowed)(const CSPHashValue&, ContentSecurityPolicy::InlineType) const>
+bool isAllowedByAllWithHash(const CSPDirectiveListVector& policies, const CSPHashValue& hashValue, ContentSecurityPolicy::InlineType type)
 {
     for (const auto& policy : policies) {
-        if (!(policy.get()->*allowed)(hashValue))
+        if (!(policy.get()->*allowed)(hashValue, type))
             return false;
     }
     return true;
@@ -405,8 +405,8 @@
     return true;
 }
 
-template<bool (CSPDirectiveList::*allowed)(const CSPHashValue&) const>
-bool checkDigest(const String& source, uint8_t hashAlgorithmsUsed, const CSPDirectiveListVector& policies)
+template<bool (CSPDirectiveList::*allowed)(const CSPHashValue&, ContentSecurityPolicy::InlineType) const>
+bool checkDigest(const String& source, ContentSecurityPolicy::InlineType type, uint8_t hashAlgorithmsUsed, const CSPDirectiveListVector& policies)
 {
     // Any additions or subtractions from this struct should also modify the
     // respective entries in the kSupportedPrefixes array in
@@ -431,7 +431,7 @@
         DigestValue digest;
         if (algorithmMap.cspHashAlgorithm & hashAlgorithmsUsed) {
             bool digestSuccess = computeDigest(algorithmMap.algorithm, utf8Source.data(), utf8Source.length(), digest);
-            if (digestSuccess && isAllowedByAllWithHash<allowed>(policies, CSPHashValue(algorithmMap.cspHashAlgorithm, digest)))
+            if (digestSuccess && isAllowedByAllWithHash<allowed>(policies, CSPHashValue(algorithmMap.cspHashAlgorithm, digest), type))
                 return true;
         }
     }
@@ -444,8 +444,12 @@
     return isAllowedByAllWithContext<&CSPDirectiveList::allowJavaScriptURLs>(m_policies, contextURL, contextLine, reportingStatus);
 }
 
-bool ContentSecurityPolicy::allowInlineEventHandlers(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+bool ContentSecurityPolicy::allowInlineEventHandler(const String& source, const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus) const
 {
+    // Inline event handlers may be whitelisted by hash, if 'unsafe-hash-attributes' is present in a policy. Check
+    // against the digest of the |source| first before proceeding on to checking whether inline script is allowed.
+    if (checkDigest<&CSPDirectiveList::allowScriptHash>(source, InlineType::Attribute, m_scriptHashAlgorithmsUsed, m_policies))
+        return true;
     return isAllowedByAllWithContext<&CSPDirectiveList::allowInlineEventHandlers>(m_policies, contextURL, contextLine, reportingStatus);
 }
 
@@ -528,14 +532,14 @@
     return isAllowedByAllWithNonce<&CSPDirectiveList::allowStyleNonce>(m_policies, nonce);
 }
 
-bool ContentSecurityPolicy::allowScriptWithHash(const String& source) const
+bool ContentSecurityPolicy::allowScriptWithHash(const String& source, InlineType type) const
 {
-    return checkDigest<&CSPDirectiveList::allowScriptHash>(source, m_scriptHashAlgorithmsUsed, m_policies);
+    return checkDigest<&CSPDirectiveList::allowScriptHash>(source, type, m_scriptHashAlgorithmsUsed, m_policies);
 }
 
-bool ContentSecurityPolicy::allowStyleWithHash(const String& source) const
+bool ContentSecurityPolicy::allowStyleWithHash(const String& source, InlineType type) const
 {
-    return checkDigest<&CSPDirectiveList::allowStyleHash>(source, m_styleHashAlgorithmsUsed, m_policies);
+    return checkDigest<&CSPDirectiveList::allowStyleHash>(source, type, m_styleHashAlgorithmsUsed, m_policies);
 }
 
 bool ContentSecurityPolicy::allowRequest(WebURLRequest::RequestContext context, const KURL& url, RedirectStatus redirectStatus, ReportingStatus reportingStatus) const
diff --git a/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.h b/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.h
index 2e410f6..f9e2466 100644
--- a/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.h
+++ b/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.h
@@ -129,6 +129,11 @@
         URLViolation
     };
 
+    enum class InlineType {
+        Block,
+        Attribute
+    };
+
     static ContentSecurityPolicy* create()
     {
         return new ContentSecurityPolicy();
@@ -146,7 +151,7 @@
     PassOwnPtr<Vector<CSPHeaderAndType>> headers() const;
 
     bool allowJavaScriptURLs(const String& contextURL, const WTF::OrdinalNumber& contextLine, ReportingStatus = SendReport) const;
-    bool allowInlineEventHandlers(const String& contextURL, const WTF::OrdinalNumber& contextLine, ReportingStatus = SendReport) const;
+    bool allowInlineEventHandler(const String& source, const String& contextURL, const WTF::OrdinalNumber& contextLine, ReportingStatus = SendReport) const;
     bool allowInlineScript(const String& contextURL, const WTF::OrdinalNumber& contextLine, const String& scriptContent, ReportingStatus = SendReport) const;
     bool allowInlineStyle(const String& contextURL, const WTF::OrdinalNumber& contextLine, const String& styleContent, ReportingStatus = SendReport) const;
     // When the reporting status is |SendReport|, the |ExceptionStatus|
@@ -193,8 +198,8 @@
     // issue a load and be safe disabling any further CSP checks.
     bool allowScriptWithNonce(const String& nonce) const;
     bool allowStyleWithNonce(const String& nonce) const;
-    bool allowScriptWithHash(const String& source) const;
-    bool allowStyleWithHash(const String& source) const;
+    bool allowScriptWithHash(const String& source, InlineType) const;
+    bool allowStyleWithHash(const String& source, InlineType) const;
 
     bool allowRequest(WebURLRequest::RequestContext, const KURL&, RedirectStatus = DidNotRedirect, ReportingStatus = SendReport) const;
 
diff --git a/third_party/WebKit/Source/core/frame/csp/SourceListDirective.cpp b/third_party/WebKit/Source/core/frame/csp/SourceListDirective.cpp
index b1d3412..78b3323 100644
--- a/third_party/WebKit/Source/core/frame/csp/SourceListDirective.cpp
+++ b/third_party/WebKit/Source/core/frame/csp/SourceListDirective.cpp
@@ -52,6 +52,11 @@
     return m_sourceList.allowHash(hashValue);
 }
 
+bool SourceListDirective::allowHashedAttributes() const
+{
+    return m_sourceList.allowHashedAttributes();
+}
+
 bool SourceListDirective::isHashOrNoncePresent() const
 {
     return m_sourceList.isHashOrNoncePresent();
diff --git a/third_party/WebKit/Source/core/frame/csp/SourceListDirective.h b/third_party/WebKit/Source/core/frame/csp/SourceListDirective.h
index 97adb21..d00ee36 100644
--- a/third_party/WebKit/Source/core/frame/csp/SourceListDirective.h
+++ b/third_party/WebKit/Source/core/frame/csp/SourceListDirective.h
@@ -29,6 +29,7 @@
     bool allowDynamic() const;
     bool allowNonce(const String& nonce) const;
     bool allowHash(const CSPHashValue&) const;
+    bool allowHashedAttributes() const;
     bool isHashOrNoncePresent() const;
     uint8_t hashAlgorithmsUsed() const;
 
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.cpp b/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.cpp
index 9d89f0c9..17c1e81 100644
--- a/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.cpp
+++ b/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.cpp
@@ -31,13 +31,9 @@
 
 namespace blink {
 
-CanvasRenderingContext::CanvasRenderingContext(HTMLCanvasElement* canvas)
+CanvasRenderingContext::CanvasRenderingContext(HTMLCanvasElement* canvas, OffscreenCanvas* offscreenCanvas)
     : m_canvas(canvas)
-{
-}
-
-CanvasRenderingContext::CanvasRenderingContext(OffscreenCanvas* canvas)
-    : m_offscreenCanvas(canvas)
+    , m_offscreenCanvas(offscreenCanvas)
 {
 }
 
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.h b/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.h
index 88d3e53..315aebe 100644
--- a/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.h
+++ b/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.h
@@ -73,7 +73,8 @@
     virtual bool hasAlpha() const { return true; }
     virtual void setIsHidden(bool) = 0;
     virtual bool isContextLost() const { return true; }
-    virtual void setCanvasGetContextResult(RenderingContext&) = 0;
+    virtual void setCanvasGetContextResult(RenderingContext&) { ASSERT_NOT_REACHED(); };
+    virtual void setOffscreenCanvasGetContextResult(OffscreenRenderingContext&) { ASSERT_NOT_REACHED(); }
 
     // Return true if the content is updated.
     virtual bool paintRenderingResultsToCanvas(SourceDrawingBuffer) { return false; }
@@ -126,8 +127,7 @@
     virtual ImageBitmap* transferToImageBitmap(ExceptionState&) { return nullptr; }
 
 protected:
-    CanvasRenderingContext(HTMLCanvasElement*);
-    CanvasRenderingContext(OffscreenCanvas*);
+    CanvasRenderingContext(HTMLCanvasElement* = nullptr, OffscreenCanvas* = nullptr);
     DECLARE_VIRTUAL_TRACE();
     virtual void stop() = 0;
 
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContextFactory.h b/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContextFactory.h
index a1d94d3b..a8d3f9a 100644
--- a/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContextFactory.h
+++ b/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContextFactory.h
@@ -25,7 +25,7 @@
     virtual ~CanvasRenderingContextFactory() { }
 
     virtual CanvasRenderingContext* create(HTMLCanvasElement*, const CanvasContextCreationAttributes&, Document&) { return nullptr; }
-    virtual CanvasRenderingContext* create(OffscreenCanvas*, const CanvasContextCreationAttributes&) { return nullptr; }
+    virtual CanvasRenderingContext* create(ScriptState*, OffscreenCanvas*, const CanvasContextCreationAttributes&) { return nullptr; }
     virtual CanvasRenderingContext::ContextType getContextType() const = 0;
     virtual void onError(HTMLCanvasElement*, const String& error) {};
     virtual void onError(OffscreenCanvas*, const String& error) {};
diff --git a/third_party/WebKit/Source/core/html/imports/HTMLImportChild.cpp b/third_party/WebKit/Source/core/html/imports/HTMLImportChild.cpp
index 33bca1d..e40a404 100644
--- a/third_party/WebKit/Source/core/html/imports/HTMLImportChild.cpp
+++ b/third_party/WebKit/Source/core/html/imports/HTMLImportChild.cpp
@@ -83,7 +83,7 @@
 void HTMLImportChild::didFinishLoading()
 {
     stateWillChange();
-    if (document() && document()->styleSheets()->length() > 0)
+    if (document() && document()->styleSheets().length() > 0)
         UseCounter::count(root()->document(), UseCounter::HTMLImportsHasStyleSheets);
     V0CustomElement::didFinishLoadingImport(*(root()->document()));
 }
diff --git a/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp b/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp
index 7712195..b29be4d 100644
--- a/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp
+++ b/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp
@@ -58,7 +58,7 @@
     return image;
 }
 
-CanvasRenderingContext* OffscreenCanvas::getCanvasRenderingContext(const String& id, const CanvasContextCreationAttributes& attributes)
+CanvasRenderingContext* OffscreenCanvas::getCanvasRenderingContext(ScriptState* scriptState, const String& id, const CanvasContextCreationAttributes& attributes)
 {
     CanvasRenderingContext::ContextType contextType = CanvasRenderingContext::contextTypeFromId(id);
 
@@ -76,7 +76,7 @@
             return nullptr;
         }
     } else {
-        m_context = factory->create(this, attributes);
+        m_context = factory->create(scriptState, this, attributes);
     }
 
     return m_context.get();
diff --git a/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.h b/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.h
index 69051b8..f97398d3 100644
--- a/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.h
+++ b/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.h
@@ -16,6 +16,8 @@
 
 class CanvasContextCreationAttributes;
 class ImageBitmap;
+class OffscreenCanvasRenderingContext2DOrWebGLRenderingContextOrWebGL2RenderingContext;
+typedef OffscreenCanvasRenderingContext2DOrWebGLRenderingContextOrWebGL2RenderingContext OffscreenRenderingContext;
 
 class CORE_EXPORT OffscreenCanvas final : public GarbageCollected<OffscreenCanvas>, public ScriptWrappable {
     DEFINE_WRAPPERTYPEINFO();
@@ -36,7 +38,7 @@
     int getAssociatedCanvasId() const { return m_canvasId; }
     bool isNeutered() const { return m_isNeutered; }
     void setNeutered();
-    CanvasRenderingContext* getCanvasRenderingContext(const String&, const CanvasContextCreationAttributes&);
+    CanvasRenderingContext* getCanvasRenderingContext(ScriptState*, const String&, const CanvasContextCreationAttributes&);
     CanvasRenderingContext* renderingContext() { return m_context; }
 
     static void registerRenderingContextFactory(PassOwnPtr<CanvasRenderingContextFactory>);
diff --git a/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeModel.js b/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeModel.js
index 662a0588..946ee71 100644
--- a/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeModel.js
@@ -434,7 +434,9 @@
 
         if (this._type === WebInspector.DeviceModeModel.Type.Device) {
             var orientation = this._device.orientationByName(this._mode.orientation);
-            var outline = (this._deviceOutlineSetting.get() && Runtime.experiments.isEnabled("deviceFrames")) ? orientation.outlineInsets : new Insets(0,0,0,0);
+            var outline = new Insets(0, 0, 0, 0);
+            if (Runtime.experiments.isEnabled("deviceFrames") && this._deviceOutlineSetting.get())
+                outline = orientation.outlineInsets || outline;
             this._fitScale = this._calculateFitScale(orientation.width, orientation.height);
             if (this._device.mobile())
                 this._appliedUserAgentType = this._device.touch() ? WebInspector.DeviceModeModel.UA.Mobile : WebInspector.DeviceModeModel.UA.MobileNoTouch;
@@ -501,7 +503,7 @@
     /**
      * @param {!Size} screenSize
      * @param {!Insets} insets
-     * @param {!Insets|null} outline
+     * @param {!Insets} outline
      * @param {number} scale
      * @param {number} deviceScaleFactor
      * @param {boolean} mobile
diff --git a/third_party/WebKit/Source/modules/ModulesInitializer.cpp b/third_party/WebKit/Source/modules/ModulesInitializer.cpp
index 4024c17c..6c69430 100644
--- a/third_party/WebKit/Source/modules/ModulesInitializer.cpp
+++ b/third_party/WebKit/Source/modules/ModulesInitializer.cpp
@@ -55,6 +55,7 @@
 
     // OffscreenCanvas context types must be registered with the OffscreenCanvas.
     OffscreenCanvas::registerRenderingContextFactory(adoptPtr(new OffscreenCanvasRenderingContext2D::Factory()));
+    OffscreenCanvas::registerRenderingContextFactory(adoptPtr(new WebGLRenderingContext::Factory()));
 
     ASSERT(isInitialized());
 }
diff --git a/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.cpp b/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.cpp
index 5397f3b..1f6d8b4 100644
--- a/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.cpp
+++ b/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.cpp
@@ -849,7 +849,7 @@
         return value.getAsHTMLCanvasElement();
     if (value.isImageBitmap()) {
         if (static_cast<ImageBitmap*>(value.getAsImageBitmap())->isNeutered()) {
-            exceptionState.throwDOMException(InvalidStateError, String::format("The image source is neutered"));
+            exceptionState.throwDOMException(InvalidStateError, String::format("The image source is detached"));
             return nullptr;
         }
         return value.getAsImageBitmap();
diff --git a/third_party/WebKit/Source/modules/device_orientation/DeviceMotionEvent.cpp b/third_party/WebKit/Source/modules/device_orientation/DeviceMotionEvent.cpp
index 1c2112d..1d2c5897 100644
--- a/third_party/WebKit/Source/modules/device_orientation/DeviceMotionEvent.cpp
+++ b/third_party/WebKit/Source/modules/device_orientation/DeviceMotionEvent.cpp
@@ -48,7 +48,7 @@
 
 void DeviceMotionEvent::initDeviceMotionEvent(const AtomicString& type, bool bubbles, bool cancelable, DeviceMotionData* deviceMotionData)
 {
-    if (dispatched())
+    if (isBeingDispatched())
         return;
 
     initEvent(type, bubbles, cancelable);
diff --git a/third_party/WebKit/Source/modules/device_orientation/DeviceOrientationEvent.cpp b/third_party/WebKit/Source/modules/device_orientation/DeviceOrientationEvent.cpp
index 4bd0770..7552b71 100644
--- a/third_party/WebKit/Source/modules/device_orientation/DeviceOrientationEvent.cpp
+++ b/third_party/WebKit/Source/modules/device_orientation/DeviceOrientationEvent.cpp
@@ -46,7 +46,7 @@
 
 void DeviceOrientationEvent::initDeviceOrientationEvent(const AtomicString& type, bool bubbles, bool cancelable, const Nullable<double>& alpha, const Nullable<double>& beta, const Nullable<double>& gamma, bool absolute)
 {
-    if (dispatched())
+    if (isBeingDispatched())
         return;
 
     initEvent(type, bubbles, cancelable);
diff --git a/third_party/WebKit/Source/modules/offscreencanvas/OffscreenCanvasModules.cpp b/third_party/WebKit/Source/modules/offscreencanvas/OffscreenCanvasModules.cpp
index 4dd5050..0585db0 100644
--- a/third_party/WebKit/Source/modules/offscreencanvas/OffscreenCanvasModules.cpp
+++ b/third_party/WebKit/Source/modules/offscreencanvas/OffscreenCanvasModules.cpp
@@ -10,18 +10,16 @@
 
 namespace blink {
 
-OffscreenCanvasRenderingContext2D* OffscreenCanvasModules::getContext(OffscreenCanvas& offscreenCanvas, const String& id, const CanvasContextCreationAttributes& attributes, ExceptionState& exceptionState)
+void OffscreenCanvasModules::getContext(ScriptState* scriptState, OffscreenCanvas& offscreenCanvas, const String& id, const CanvasContextCreationAttributes& attributes, ExceptionState& exceptionState, OffscreenRenderingContext& result)
 {
     if (offscreenCanvas.isNeutered()) {
         exceptionState.throwDOMException(InvalidStateError, "OffscreenCanvas object is detached");
-        return nullptr;
+        return;
     }
 
-    CanvasRenderingContext* context = offscreenCanvas.getCanvasRenderingContext(id, attributes);
-    if (!context)
-        return nullptr;
-
-    return static_cast<OffscreenCanvasRenderingContext2D*>(context);
+    CanvasRenderingContext* context = offscreenCanvas.getCanvasRenderingContext(scriptState, id, attributes);
+    if (context)
+        context->setOffscreenCanvasGetContextResult(result);
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/modules/offscreencanvas/OffscreenCanvasModules.h b/third_party/WebKit/Source/modules/offscreencanvas/OffscreenCanvasModules.h
index 1353356..ed43b21 100644
--- a/third_party/WebKit/Source/modules/offscreencanvas/OffscreenCanvasModules.h
+++ b/third_party/WebKit/Source/modules/offscreencanvas/OffscreenCanvasModules.h
@@ -6,6 +6,7 @@
 #define OffscreenCanvasModules_h
 
 #include "bindings/core/v8/ExceptionState.h"
+#include "core/offscreencanvas/OffscreenCanvas.h"
 #include "modules/ModulesExport.h"
 #include "wtf/Allocator.h"
 #include "wtf/text/WTFString.h"
@@ -19,7 +20,7 @@
 class MODULES_EXPORT OffscreenCanvasModules {
     STATIC_ONLY(OffscreenCanvasModules)
 public:
-    static OffscreenCanvasRenderingContext2D* getContext(OffscreenCanvas&, const String&, const CanvasContextCreationAttributes&, ExceptionState&);
+    static void getContext(ScriptState*, OffscreenCanvas&, const String&, const CanvasContextCreationAttributes&, ExceptionState&, OffscreenRenderingContext&);
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/modules/offscreencanvas/OffscreenCanvasModules.idl b/third_party/WebKit/Source/modules/offscreencanvas/OffscreenCanvasModules.idl
index 17c5b73e..42dccec506 100644
--- a/third_party/WebKit/Source/modules/offscreencanvas/OffscreenCanvasModules.idl
+++ b/third_party/WebKit/Source/modules/offscreencanvas/OffscreenCanvasModules.idl
@@ -2,8 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-typedef OffscreenCanvasRenderingContext2D OffscreenRenderingContext;
+typedef (OffscreenCanvasRenderingContext2D or
+         WebGLRenderingContext or
+         WebGL2RenderingContext) OffscreenRenderingContext;
 
 partial interface OffscreenCanvas {
-    [RaisesException, RuntimeEnabled=ExperimentalCanvasFeatures] OffscreenRenderingContext? getContext(DOMString contextId, optional CanvasContextCreationAttributes attributes);
+    [CallWith=ScriptState, RaisesException, RuntimeEnabled=ExperimentalCanvasFeatures] OffscreenRenderingContext? getContext(DOMString contextId, optional CanvasContextCreationAttributes attributes);
 };
diff --git a/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.cpp b/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.cpp
index 4a60e82c..758318b 100644
--- a/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.cpp
+++ b/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.cpp
@@ -19,7 +19,7 @@
 }
 
 OffscreenCanvasRenderingContext2D::OffscreenCanvasRenderingContext2D(OffscreenCanvas* canvas, const CanvasContextCreationAttributes& attrs)
-    : CanvasRenderingContext(canvas)
+    : CanvasRenderingContext(nullptr, canvas)
     , m_hasAlpha(attrs.alpha())
 {
 }
@@ -95,6 +95,11 @@
     return ImageBitmap::create(image.release());
 }
 
+void OffscreenCanvasRenderingContext2D::setOffscreenCanvasGetContextResult(OffscreenRenderingContext& result)
+{
+    result.setOffscreenCanvasRenderingContext2D(this);
+}
+
 bool OffscreenCanvasRenderingContext2D::parseColorOrCurrentColor(Color& color, const String& colorString) const
 {
     return ::blink::parseColorOrCurrentColor(color, colorString, nullptr);
diff --git a/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.h b/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.h
index f217cdf..1db409c7 100644
--- a/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.h
+++ b/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.h
@@ -12,8 +12,6 @@
 
 namespace blink {
 
-class HTMLCanvasElement;
-
 class MODULES_EXPORT OffscreenCanvasRenderingContext2D final : public CanvasRenderingContext, public BaseRenderingContext2D {
     DEFINE_WRAPPERTYPEINFO();
     USING_GARBAGE_COLLECTED_MIXIN(OffscreenCanvasRenderingContext2D);
@@ -23,7 +21,7 @@
         Factory() {}
         ~Factory() override {}
 
-        CanvasRenderingContext* create(OffscreenCanvas* canvas, const CanvasContextCreationAttributes& attrs) override
+        CanvasRenderingContext* create(ScriptState* scriptState, OffscreenCanvas* canvas, const CanvasContextCreationAttributes& attrs) override
         {
             return new OffscreenCanvasRenderingContext2D(canvas, attrs);
         }
@@ -38,6 +36,7 @@
     ~OffscreenCanvasRenderingContext2D() override;
     ContextType getContextType() const override { return Context2d; }
     bool is2d() const override { return true; }
+    void setOffscreenCanvasGetContextResult(OffscreenRenderingContext&) final;
     void setIsHidden(bool) final { ASSERT_NOT_REACHED(); }
     void stop() final { ASSERT_NOT_REACHED(); }
     void setCanvasGetContextResult(RenderingContext&) final {}
diff --git a/third_party/WebKit/Source/modules/storage/StorageEvent.cpp b/third_party/WebKit/Source/modules/storage/StorageEvent.cpp
index b18c5032..7a91673 100644
--- a/third_party/WebKit/Source/modules/storage/StorageEvent.cpp
+++ b/third_party/WebKit/Source/modules/storage/StorageEvent.cpp
@@ -81,7 +81,7 @@
 
 void StorageEvent::initStorageEvent(const AtomicString& type, bool canBubble, bool cancelable, const String& key, const String& oldValue, const String& newValue, const String& url, Storage* storageArea)
 {
-    if (dispatched())
+    if (isBeingDispatched())
         return;
 
     initEvent(type, canBubble, cancelable);
diff --git a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContext.cpp b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContext.cpp
index 671319c..1da246a 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContext.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContext.cpp
@@ -83,6 +83,17 @@
     result.setWebGL2RenderingContext(this);
 }
 
+void WebGL2RenderingContext::setOffscreenCanvasGetContextResult(OffscreenRenderingContext& result)
+{
+    result.setWebGL2RenderingContext(this);
+}
+
+ImageBitmap* WebGL2RenderingContext::transferToImageBitmap(ExceptionState& exceptionState)
+{
+    NOTIMPLEMENTED();
+    return nullptr;
+}
+
 void WebGL2RenderingContext::registerContextExtensions()
 {
     // Register extensions.
diff --git a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContext.h b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContext.h
index 61ad255..899faac 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContext.h
+++ b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContext.h
@@ -30,10 +30,12 @@
     ~WebGL2RenderingContext() override;
 
     CanvasRenderingContext::ContextType getContextType() const override { return CanvasRenderingContext::ContextWebgl2; }
+    ImageBitmap* transferToImageBitmap(ExceptionState&) final;
     unsigned version() const override { return 2; }
     String contextName() const override { return "WebGL2RenderingContext"; }
     void registerContextExtensions() override;
     void setCanvasGetContextResult(RenderingContext&) final;
+    void setOffscreenCanvasGetContextResult(OffscreenRenderingContext&) final;
 
     DECLARE_VIRTUAL_TRACE();
 
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContext.cpp b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContext.cpp
index abd64cd..cc46e80 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContext.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContext.cpp
@@ -65,28 +65,51 @@
 
 namespace blink {
 
+// An helper function for the two create() methods. The return value is an
+// indicate of whether the create() should return nullptr or not.
+static bool shouldCreateContext(WebGraphicsContext3DProvider* contextProvider)
+{
+    if (!contextProvider)
+        return false;
+    gpu::gles2::GLES2Interface* gl = contextProvider->contextGL();
+    OwnPtr<Extensions3DUtil> extensionsUtil = Extensions3DUtil::create(gl);
+    if (!extensionsUtil)
+        return false;
+    if (extensionsUtil->supportsExtension("GL_EXT_debug_marker")) {
+        String contextLabel(String::format("WebGLRenderingContext-%p", contextProvider));
+        gl->PushGroupMarkerEXT(0, contextLabel.ascii().data());
+    }
+    return true;
+}
+
+CanvasRenderingContext* WebGLRenderingContext::Factory::create(ScriptState* scriptState, OffscreenCanvas* offscreenCanvas, const CanvasContextCreationAttributes& attrs)
+{
+    WebGLContextAttributes attributes = toWebGLContextAttributes(attrs);
+    OwnPtr<WebGraphicsContext3DProvider> contextProvider(createWebGraphicsContext3DProvider(scriptState, attributes, 1));
+    if (!shouldCreateContext(contextProvider.get()))
+        return nullptr;
+
+    WebGLRenderingContext* renderingContext = new WebGLRenderingContext(offscreenCanvas, contextProvider.release(), attributes);
+    if (!renderingContext->drawingBuffer())
+        return nullptr;
+    renderingContext->initializeNewContext();
+    renderingContext->registerContextExtensions();
+
+    return renderingContext;
+}
+
 CanvasRenderingContext* WebGLRenderingContext::Factory::create(HTMLCanvasElement* canvas, const CanvasContextCreationAttributes& attrs, Document&)
 {
     WebGLContextAttributes attributes = toWebGLContextAttributes(attrs);
     OwnPtr<WebGraphicsContext3DProvider> contextProvider(createWebGraphicsContext3DProvider(canvas, attributes, 1));
-    if (!contextProvider)
+    if (!shouldCreateContext(contextProvider.get()))
         return nullptr;
-    gpu::gles2::GLES2Interface* gl = contextProvider->contextGL();
-    OwnPtr<Extensions3DUtil> extensionsUtil = Extensions3DUtil::create(gl);
-    if (!extensionsUtil)
-        return nullptr;
-    if (extensionsUtil->supportsExtension("GL_EXT_debug_marker")) {
-        String contextLabel(String::format("WebGLRenderingContext-%p", contextProvider.get()));
-        gl->PushGroupMarkerEXT(0, contextLabel.ascii().data());
-    }
 
     WebGLRenderingContext* renderingContext = new WebGLRenderingContext(canvas, contextProvider.release(), attributes);
-
     if (!renderingContext->drawingBuffer()) {
         canvas->dispatchEvent(WebGLContextEvent::create(EventTypeNames::webglcontextcreationerror, false, true, "Could not create a WebGL context."));
         return nullptr;
     }
-
     renderingContext->initializeNewContext();
     renderingContext->registerContextExtensions();
 
@@ -103,6 +126,11 @@
 {
 }
 
+WebGLRenderingContext::WebGLRenderingContext(OffscreenCanvas* passedOffscreenCanvas, PassOwnPtr<WebGraphicsContext3DProvider> contextProvider, const WebGLContextAttributes& requestedAttributes)
+    : WebGLRenderingContextBase(passedOffscreenCanvas, std::move(contextProvider), requestedAttributes)
+{
+}
+
 WebGLRenderingContext::~WebGLRenderingContext()
 {
 }
@@ -112,6 +140,17 @@
     result.setWebGLRenderingContext(this);
 }
 
+void WebGLRenderingContext::setOffscreenCanvasGetContextResult(OffscreenRenderingContext& result)
+{
+    result.setWebGLRenderingContext(this);
+}
+
+ImageBitmap* WebGLRenderingContext::transferToImageBitmap(ExceptionState& exceptionState)
+{
+    NOTIMPLEMENTED();
+    return nullptr;
+}
+
 void WebGLRenderingContext::registerContextExtensions()
 {
     // Register extensions.
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContext.h b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContext.h
index e0f6a0b3..b2f6548 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContext.h
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContext.h
@@ -43,6 +43,7 @@
         ~Factory() override {}
 
         CanvasRenderingContext* create(HTMLCanvasElement*, const CanvasContextCreationAttributes&, Document&) override;
+        CanvasRenderingContext* create(ScriptState*, OffscreenCanvas*, const CanvasContextCreationAttributes&) override;
         CanvasRenderingContext::ContextType getContextType() const override { return CanvasRenderingContext::ContextWebgl; }
         void onError(HTMLCanvasElement*, const String& error) override;
     };
@@ -50,16 +51,19 @@
     ~WebGLRenderingContext() override;
 
     CanvasRenderingContext::ContextType getContextType() const override { return CanvasRenderingContext::ContextWebgl; }
+    ImageBitmap* transferToImageBitmap(ExceptionState&) final;
     unsigned version() const override { return 1; }
     String contextName() const override { return "WebGLRenderingContext"; }
     void registerContextExtensions() override;
     void setCanvasGetContextResult(RenderingContext&) final;
+    void setOffscreenCanvasGetContextResult(OffscreenRenderingContext&) final;
 
     EAGERLY_FINALIZE();
     DECLARE_VIRTUAL_TRACE();
 
 private:
     WebGLRenderingContext(HTMLCanvasElement*, PassOwnPtr<WebGraphicsContext3DProvider>, const WebGLContextAttributes&);
+    WebGLRenderingContext(OffscreenCanvas*, PassOwnPtr<WebGraphicsContext3DProvider>, const WebGLContextAttributes&);
 
     // Enabled extension objects.
     Member<ANGLEInstancedArrays> m_angleInstancedArrays;
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
index 999af82..828b8752 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
@@ -503,6 +503,34 @@
     return statusMessage;
 }
 
+static PassOwnPtr<WebGraphicsContext3DProvider> createWebGraphicsContext3DProviderInternal(HTMLCanvasElement* canvas, ScriptState* scriptState, WebGLContextAttributes attributes, unsigned webGLVersion)
+{
+    Platform::ContextAttributes contextAttributes = toPlatformContextAttributes(attributes, webGLVersion);
+    Platform::GraphicsInfo glInfo;
+    OwnPtr<WebGraphicsContext3DProvider> contextProvider;
+    if (canvas) {
+        contextProvider = adoptPtr(Platform::current()->createOffscreenGraphicsContext3DProvider(
+            contextAttributes, canvas->document().topDocument().url(), 0, &glInfo));
+    } else {
+        contextProvider = adoptPtr(Platform::current()->createOffscreenGraphicsContext3DProvider(
+            contextAttributes, scriptState->getExecutionContext()->url(), 0, &glInfo));
+    }
+    if (!contextProvider || shouldFailContextCreationForTesting) {
+        shouldFailContextCreationForTesting = false;
+        if (canvas)
+            canvas->dispatchEvent(WebGLContextEvent::create(EventTypeNames::webglcontextcreationerror, false, true, extractWebGLContextCreationError(glInfo)));
+        return nullptr;
+    }
+    gpu::gles2::GLES2Interface* gl = contextProvider->contextGL();
+    if (!String(gl->GetString(GL_EXTENSIONS)).contains("GL_OES_packed_depth_stencil")) {
+        if (canvas)
+            canvas->dispatchEvent(WebGLContextEvent::create(EventTypeNames::webglcontextcreationerror, false, true, "OES_packed_depth_stencil support is required."));
+        return nullptr;
+    }
+
+    return contextProvider.release();
+}
+
 PassOwnPtr<WebGraphicsContext3DProvider> WebGLRenderingContextBase::createWebGraphicsContext3DProvider(HTMLCanvasElement* canvas, WebGLContextAttributes attributes, unsigned webGLVersion)
 {
     Document& document = canvas->document();
@@ -520,22 +548,12 @@
         return nullptr;
     }
 
-    Platform::ContextAttributes contextAttributes = toPlatformContextAttributes(attributes, webGLVersion);
-    Platform::GraphicsInfo glInfo;
-    OwnPtr<WebGraphicsContext3DProvider> contextProvider = adoptPtr(Platform::current()->createOffscreenGraphicsContext3DProvider(
-        contextAttributes, document.topDocument().url(), 0, &glInfo));
-    if (!contextProvider || shouldFailContextCreationForTesting) {
-        shouldFailContextCreationForTesting = false;
-        canvas->dispatchEvent(WebGLContextEvent::create(EventTypeNames::webglcontextcreationerror, false, true, extractWebGLContextCreationError(glInfo)));
-        return nullptr;
-    }
-    gpu::gles2::GLES2Interface* gl = contextProvider->contextGL();
-    if (!String(gl->GetString(GL_EXTENSIONS)).contains("GL_OES_packed_depth_stencil")) {
-        canvas->dispatchEvent(WebGLContextEvent::create(EventTypeNames::webglcontextcreationerror, false, true, "OES_packed_depth_stencil support is required."));
-        return nullptr;
-    }
+    return createWebGraphicsContext3DProviderInternal(canvas, nullptr, attributes, webGLVersion);
+}
 
-    return contextProvider.release();
+PassOwnPtr<WebGraphicsContext3DProvider> WebGLRenderingContextBase::createWebGraphicsContext3DProvider(ScriptState* scriptState, WebGLContextAttributes attributes, unsigned webGLVersion)
+{
+    return createWebGraphicsContext3DProviderInternal(nullptr, scriptState, attributes, webGLVersion);
 }
 
 void WebGLRenderingContextBase::forceNextWebGLContextCreationToFail()
@@ -780,8 +798,16 @@
 
 } // namespace
 
+WebGLRenderingContextBase::WebGLRenderingContextBase(OffscreenCanvas* passedOffscreenCanvas, PassOwnPtr<WebGraphicsContext3DProvider> contextProvider, const WebGLContextAttributes& requestedAttributes)
+    : WebGLRenderingContextBase(nullptr, passedOffscreenCanvas, std::move(contextProvider), requestedAttributes)
+{ }
+
 WebGLRenderingContextBase::WebGLRenderingContextBase(HTMLCanvasElement* passedCanvas, PassOwnPtr<WebGraphicsContext3DProvider> contextProvider, const WebGLContextAttributes& requestedAttributes)
-    : CanvasRenderingContext(passedCanvas)
+    : WebGLRenderingContextBase(passedCanvas, nullptr, std::move(contextProvider), requestedAttributes)
+{ }
+
+WebGLRenderingContextBase::WebGLRenderingContextBase(HTMLCanvasElement* passedCanvas, OffscreenCanvas* passedOffscreenCanvas, PassOwnPtr<WebGraphicsContext3DProvider> contextProvider, const WebGLContextAttributes& requestedAttributes)
+    : CanvasRenderingContext(passedCanvas, passedOffscreenCanvas)
     , m_isHidden(false)
     , m_contextLostMode(NotLostContext)
     , m_autoRecoveryMethod(Manual)
@@ -976,8 +1002,10 @@
 void WebGLRenderingContextBase::setupFlags()
 {
     ASSERT(drawingBuffer());
-    if (Page* p = canvas()->document().page()) {
-        m_synthesizedErrorsToConsole = p->settings().webGLErrorsToConsoleEnabled();
+    if (canvas()) {
+        if (Page* p = canvas()->document().page()) {
+            m_synthesizedErrorsToConsole = p->settings().webGLErrorsToConsoleEnabled();
+        }
     }
 
     m_isDepthStencilSupported = extensionsUtil()->isExtensionEnabled("GL_OES_packed_depth_stencil");
@@ -5790,7 +5818,7 @@
 bool WebGLRenderingContextBase::validateImageBitmap(const char* functionName, ImageBitmap* bitmap, ExceptionState& exceptionState)
 {
     if (bitmap->isNeutered()) {
-        synthesizeGLError(GL_INVALID_VALUE, functionName, "The source data has been neutered.");
+        synthesizeGLError(GL_INVALID_VALUE, functionName, "The source data has been detached.");
         return false;
     }
     if (!bitmap->originClean()) {
@@ -6044,8 +6072,16 @@
 
 IntSize WebGLRenderingContextBase::clampedCanvasSize()
 {
-    return IntSize(clamp(canvas()->width(), 1, m_maxViewportDims[0]),
-        clamp(canvas()->height(), 1, m_maxViewportDims[1]));
+    int width, height;
+    if (canvas()) {
+        width = canvas()->width();
+        height = canvas()->height();
+    } else {
+        width = getOffscreenCanvas()->width();
+        height = getOffscreenCanvas()->height();
+    }
+    return IntSize(clamp(width, 1, m_maxViewportDims[0]),
+        clamp(height, 1, m_maxViewportDims[1]));
 }
 
 GLint WebGLRenderingContextBase::maxDrawBuffers()
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
index 488589a..97edb87 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
@@ -152,6 +152,7 @@
     static unsigned getWebGLVersion(const CanvasRenderingContext*);
 
     static PassOwnPtr<WebGraphicsContext3DProvider> createWebGraphicsContext3DProvider(HTMLCanvasElement*, WebGLContextAttributes, unsigned webGLVersion);
+    static PassOwnPtr<WebGraphicsContext3DProvider> createWebGraphicsContext3DProvider(ScriptState*, WebGLContextAttributes, unsigned webGLVersion);
     static void forceNextWebGLContextCreationToFail();
 
     int drawingBufferWidth() const;
@@ -443,6 +444,7 @@
     friend class ScopedFramebufferRestorer;
 
     WebGLRenderingContextBase(HTMLCanvasElement*, PassOwnPtr<WebGraphicsContext3DProvider>, const WebGLContextAttributes&);
+    WebGLRenderingContextBase(OffscreenCanvas*, PassOwnPtr<WebGraphicsContext3DProvider>, const WebGLContextAttributes&);
     PassRefPtr<DrawingBuffer> createDrawingBuffer(PassOwnPtr<WebGraphicsContext3DProvider>);
     void setupFlags();
 
@@ -1074,6 +1076,9 @@
     static WebGLRenderingContextBase* oldestEvictedContext();
 
     CrossThreadWeakPersistentThisPointer<WebGLRenderingContextBase> createWeakThisPointer() { return CrossThreadWeakPersistentThisPointer<WebGLRenderingContextBase>(this); }
+
+private:
+    WebGLRenderingContextBase(HTMLCanvasElement*, OffscreenCanvas*, PassOwnPtr<WebGraphicsContext3DProvider>, const WebGLContextAttributes&);
 };
 
 DEFINE_TYPE_CASTS(WebGLRenderingContextBase, CanvasRenderingContext, context, context->is3d(), context.is3d());
diff --git a/third_party/WebKit/Source/platform/CrossThreadCopier.h b/third_party/WebKit/Source/platform/CrossThreadCopier.h
index de30baa0..e29e8411 100644
--- a/third_party/WebKit/Source/platform/CrossThreadCopier.h
+++ b/third_party/WebKit/Source/platform/CrossThreadCopier.h
@@ -158,16 +158,6 @@
 };
 
 template <typename T>
-struct CrossThreadCopier<WeakMember<T>*> {
-    STATIC_ONLY(CrossThreadCopier);
-    typedef WeakMember<T>* Type;
-    static Type copy(Type ptr)
-    {
-        return ptr;
-    }
-};
-
-template <typename T>
 struct CrossThreadCopier<WTF::PassedWrapper<T>> {
     STATIC_ONLY(CrossThreadCopier);
     using Type = WTF::PassedWrapper<typename CrossThreadCopier<T>::Type>;
@@ -225,25 +215,20 @@
     }
 };
 
-template <typename T>
-struct CrossThreadCopier<WeakMember<T>> {
-    STATIC_ONLY(CrossThreadCopier);
-    static_assert(IsGarbageCollectedType<T>::value, "T must be a garbage-collected type.");
-    typedef T* Type;
-    static Type copy(const WeakMember<T>& ptr)
-    {
-        return ptr;
-    }
-};
-
 // |T| is |C*| or |const WeakPtr<C>&|.
 template <typename T>
 struct AllowCrossThreadAccessWrapper {
     STACK_ALLOCATED();
 public:
-    explicit AllowCrossThreadAccessWrapper(T value) : m_value(value) { }
     T value() const { return m_value; }
 private:
+    // Only constructible from AllowCrossThreadAccess().
+    explicit AllowCrossThreadAccessWrapper(T value) : m_value(value) { }
+    template <typename U>
+    friend AllowCrossThreadAccessWrapper<U*> AllowCrossThreadAccess(U*);
+    template <typename U>
+    friend AllowCrossThreadAccessWrapper<const WeakPtr<U>&> AllowCrossThreadAccess(const WeakPtr<U>&);
+
     // This raw pointer is safe since AllowCrossThreadAccessWrapper is
     // always stack-allocated. Ideally this should be Member<T> if T is
     // garbage-collected and T* otherwise, but we don't want to introduce
diff --git a/third_party/WebKit/Source/platform/fonts/FontDataForRangeSet.h b/third_party/WebKit/Source/platform/fonts/FontDataForRangeSet.h
index 42091042..a31bb4727 100644
--- a/third_party/WebKit/Source/platform/fonts/FontDataForRangeSet.h
+++ b/third_party/WebKit/Source/platform/fonts/FontDataForRangeSet.h
@@ -38,17 +38,8 @@
 
 class FontDataForRangeSet final {
     DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
-    explicit FontDataForRangeSet(PassRefPtr<SimpleFontData> fontData)
-        : m_fontData(fontData)
-    {
-    }
 
-    FontDataForRangeSet()
-        : m_fontData(nullptr)
-    {
-    }
-
-    explicit FontDataForRangeSet(PassRefPtr<SimpleFontData> fontData, PassRefPtr<UnicodeRangeSet> rangeSet)
+    explicit FontDataForRangeSet(PassRefPtr<SimpleFontData> fontData = nullptr, PassRefPtr<UnicodeRangeSet> rangeSet = nullptr)
         : m_fontData(fontData)
         , m_rangeSet(rangeSet)
     {
@@ -67,9 +58,9 @@
 
     bool contains(UChar32 testChar) const { return m_rangeSet->contains(testChar); }
     bool isEntireRange() const { return m_rangeSet->isEntireRange(); }
-    PassRefPtr<UnicodeRangeSet> ranges() const { return m_rangeSet; }
-    bool hasFontData() const { return fontData(); }
-    PassRefPtr<SimpleFontData> fontData() const { return m_fontData; }
+    UnicodeRangeSet* ranges() const { return m_rangeSet.get(); }
+    bool hasFontData() const { return m_fontData.get(); }
+    const SimpleFontData* fontData() const { return m_fontData.get(); }
 
 private:
     RefPtr<SimpleFontData> m_fontData;
diff --git a/third_party/WebKit/Source/platform/fonts/FontFallbackIterator.cpp b/third_party/WebKit/Source/platform/fonts/FontFallbackIterator.cpp
index 7467c93..c1c0ca9 100644
--- a/third_party/WebKit/Source/platform/fonts/FontFallbackIterator.cpp
+++ b/third_party/WebKit/Source/platform/fonts/FontFallbackIterator.cpp
@@ -154,9 +154,10 @@
     }
 
     if (rangeSetContributesForHint(hintList, currentSegmentedFace)) {
-        if (currentSegmentedFace.fontData()->customFontData())
-            currentSegmentedFace.fontData()->customFontData()->beginLoadIfNeeded();
-        if (!currentSegmentedFace.fontData()->isLoading())
+        const SimpleFontData* fontData = currentSegmentedFace.fontData();
+        if (const CustomFontData* customFontData = fontData->customFontData())
+            customFontData->beginLoadIfNeeded();
+        if (!fontData->isLoading())
             return currentSegmentedFace;
         m_trackedLoadingRangeSets.append(currentSegmentedFace);
     }
diff --git a/third_party/WebKit/Source/platform/fonts/FontFallbackList.cpp b/third_party/WebKit/Source/platform/fonts/FontFallbackList.cpp
index 713ed39..71d1851 100644
--- a/third_party/WebKit/Source/platform/fonts/FontFallbackList.cpp
+++ b/third_party/WebKit/Source/platform/fonts/FontFallbackList.cpp
@@ -134,7 +134,7 @@
         if (fontData->isSegmented()) {
             const SegmentedFontData* segmented = toSegmentedFontData(fontData);
             for (unsigned i = 0; i < segmented->numFaces(); i++) {
-                const SimpleFontData* rangeFontData = segmented->faceAt(i).fontData().get();
+                const SimpleFontData* rangeFontData = segmented->faceAt(i).fontData();
                 if (!rangeFontData->isLoadingFallback())
                     return rangeFontData;
             }
diff --git a/third_party/WebKit/Source/platform/fonts/GlyphPageTreeNode.cpp b/third_party/WebKit/Source/platform/fonts/GlyphPageTreeNode.cpp
index 9bd9479..d0b99cf 100644
--- a/third_party/WebKit/Source/platform/fonts/GlyphPageTreeNode.cpp
+++ b/third_party/WebKit/Source/platform/fonts/GlyphPageTreeNode.cpp
@@ -278,7 +278,7 @@
                     continue;
                 }
 
-                haveGlyphs |= fill(m_page.get(), from, to - from, buffer + from * (start < 0x10000 ? 1 : 2), (to - from) * (start < 0x10000 ? 1 : 2), fontDataForRangeSet.fontData().get());
+                haveGlyphs |= fill(m_page.get(), from, to - from, buffer + from * (start < 0x10000 ? 1 : 2), (to - from) * (start < 0x10000 ? 1 : 2), fontDataForRangeSet.fontData());
             }
         }
     }
diff --git a/third_party/WebKit/Source/platform/fonts/SegmentedFontData.cpp b/third_party/WebKit/Source/platform/fonts/SegmentedFontData.cpp
index e2f00607..05fe81f 100644
--- a/third_party/WebKit/Source/platform/fonts/SegmentedFontData.cpp
+++ b/third_party/WebKit/Source/platform/fonts/SegmentedFontData.cpp
@@ -41,9 +41,9 @@
     Vector<FontDataForRangeSet>::const_iterator end = m_faces.end();
     for (Vector<FontDataForRangeSet>::const_iterator it = m_faces.begin(); it != end; ++it) {
         if (it->contains(c))
-            return it->fontData().get();
+            return it->fontData();
     }
-    return m_faces[0].fontData().get();
+    return m_faces[0].fontData();
 }
 
 bool SegmentedFontData::containsCharacter(UChar32 c) const
diff --git a/third_party/WebKit/Source/platform/fonts/SimpleFontData.h b/third_party/WebKit/Source/platform/fonts/SimpleFontData.h
index eed56b4..03a087c 100644
--- a/third_party/WebKit/Source/platform/fonts/SimpleFontData.h
+++ b/third_party/WebKit/Source/platform/fonts/SimpleFontData.h
@@ -122,7 +122,7 @@
 
     bool canRenderCombiningCharacterSequence(const UChar*, size_t) const;
 
-    PassRefPtr<CustomFontData> customFontData() const { return m_customFontData; }
+    CustomFontData* customFontData() const { return m_customFontData.get(); }
 
     // Implemented by the platform.
     virtual bool fillGlyphPage(GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength) const;
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp
index d2e90d4..204da72b 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp
+++ b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp
@@ -80,11 +80,6 @@
     DestroyFunction m_destroy;
 };
 
-static inline float harfBuzzPositionToFloat(hb_position_t value)
-{
-    return static_cast<float>(value) / (1 << 16);
-}
-
 static void normalizeCharacters(const TextRun& run, unsigned length, UChar* destination, unsigned* destinationLength)
 {
     unsigned position = 0;
@@ -436,14 +431,16 @@
         // When we're getting here with the last resort font, we have no other
         // choice than adding boxes to the ShapeResult.
         if ((currentClusterResult == NotDef && numCharacters) || isLastResort) {
+            hb_direction_t direction = TextDirectionToHBDirection(
+                m_textRun.direction(),
+                m_font->getFontDescription().orientation(), currentFont);
             // Here we need to specify glyph positions.
-            OwnPtr<ShapeResult::RunInfo> run = adoptPtr(new ShapeResult::RunInfo(currentFont,
-                TextDirectionToHBDirection(m_textRun.direction(),
-                m_font->getFontDescription().orientation(), currentFont),
-                ICUScriptToHBScript(currentRunScript),
-                startIndex,
-                numGlyphsToInsert, numCharacters));
-            insertRunIntoShapeResult(shapeResult, run.release(), lastChangePosition, numGlyphsToInsert, harfBuzzBuffer);
+            ShapeResult::RunInfo* run = new ShapeResult::RunInfo(currentFont,
+                direction, ICUScriptToHBScript(currentRunScript),
+                startIndex, numGlyphsToInsert, numCharacters);
+            shapeResult->insertRun(adoptPtr(run), lastChangePosition,
+                numGlyphsToInsert,
+                harfBuzzBuffer);
         }
         lastChangePosition = glyphIndex;
     }
@@ -588,7 +585,7 @@
                 }
 
                 FontDataForRangeSet nextFontDataForRangeSet = fallbackIterator->next(fallbackCharsHint);
-                currentFont = nextFontDataForRangeSet.fontData().get();
+                currentFont = nextFontDataForRangeSet.fontData();
                 currentFontRangeSet = nextFontDataForRangeSet.ranges();
 
                 if (!currentFont) {
@@ -661,81 +658,6 @@
     return result.release();
 }
 
-// TODO crbug.com/542701: This should be a method on ShapeResult.
-void HarfBuzzShaper::insertRunIntoShapeResult(ShapeResult* result,
-    PassOwnPtr<ShapeResult::RunInfo> runToInsert, unsigned startGlyph, unsigned numGlyphs,
-    hb_buffer_t* harfBuzzBuffer)
-{
-    ASSERT(numGlyphs > 0);
-    OwnPtr<ShapeResult::RunInfo> run(std::move(runToInsert));
-    ASSERT(numGlyphs == run->m_glyphData.size());
-
-    const SimpleFontData* currentFontData = run->m_fontData.get();
-    const hb_glyph_info_t* glyphInfos = hb_buffer_get_glyph_infos(harfBuzzBuffer, 0);
-    const hb_glyph_position_t* glyphPositions = hb_buffer_get_glyph_positions(harfBuzzBuffer, 0);
-    const unsigned startCluster = HB_DIRECTION_IS_FORWARD(hb_buffer_get_direction(harfBuzzBuffer))
-        ? glyphInfos[startGlyph].cluster : glyphInfos[startGlyph + numGlyphs - 1].cluster;
-
-    float totalAdvance = 0.0f;
-    FloatPoint glyphOrigin;
-    bool hasVerticalOffsets = !HB_DIRECTION_IS_HORIZONTAL(run->m_direction);
-
-    // HarfBuzz returns result in visual order, no need to flip for RTL.
-    for (unsigned i = 0; i < numGlyphs; ++i) {
-        uint16_t glyph = glyphInfos[startGlyph + i].codepoint;
-        float offsetX = harfBuzzPositionToFloat(glyphPositions[startGlyph + i].x_offset);
-        float offsetY = -harfBuzzPositionToFloat(glyphPositions[startGlyph + i].y_offset);
-
-        // One out of x_advance and y_advance is zero, depending on
-        // whether the buffer direction is horizontal or vertical.
-        float advance = harfBuzzPositionToFloat(glyphPositions[startGlyph + i].x_advance - glyphPositions[startGlyph + i].y_advance);
-        RELEASE_ASSERT(m_normalizedBufferLength > glyphInfos[startGlyph + i].cluster);
-
-        // The characterIndex of one ShapeResult run is normalized to the run's
-        // startIndex and length.  TODO crbug.com/542703: Consider changing that
-        // and instead pass the whole run to hb_buffer_t each time.
-        run->m_glyphData[i].characterIndex = glyphInfos[startGlyph + i].cluster - startCluster;
-
-        run->setGlyphAndPositions(i, glyph, advance, offsetX, offsetY);
-        totalAdvance += advance;
-        hasVerticalOffsets |= (offsetY != 0);
-
-        FloatRect glyphBounds = currentFontData->boundsForGlyph(glyph);
-        glyphBounds.move(glyphOrigin.x(), glyphOrigin.y());
-        result->m_glyphBoundingBox.unite(glyphBounds);
-        glyphOrigin += FloatSize(advance + offsetX, offsetY);
-    }
-    run->m_width = std::max(0.0f, totalAdvance);
-    result->m_width += run->m_width;
-    result->m_numGlyphs += numGlyphs;
-    ASSERT(result->m_numGlyphs >= numGlyphs); // no overflow
-    result->m_hasVerticalOffsets |= hasVerticalOffsets;
-
-    // The runs are stored in result->m_runs in visual order. For LTR, we place
-    // the run to be inserted before the next run with a bigger character
-    // start index. For RTL, we place the run before the next run with a lower
-    // character index. Otherwise, for both directions, at the end.
-    if (HB_DIRECTION_IS_FORWARD(run->m_direction)) {
-        for (size_t pos = 0; pos < result->m_runs.size(); ++pos) {
-            if (result->m_runs.at(pos)->m_startIndex > run->m_startIndex) {
-                result->m_runs.insert(pos, run.release());
-                break;
-            }
-        }
-    } else {
-        for (size_t pos = 0; pos < result->m_runs.size(); ++pos) {
-            if (result->m_runs.at(pos)->m_startIndex < run->m_startIndex) {
-                result->m_runs.insert(pos, run.release());
-                break;
-            }
-        }
-    }
-    // If we didn't find an existing slot to place it, append.
-    if (run) {
-        result->m_runs.append(run.release());
-    }
-}
-
 PassRefPtr<ShapeResult> ShapeResult::createForTabulationCharacters(const Font* font,
     const TextRun& textRun, float positionOffset, unsigned count)
 {
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.cpp b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.cpp
index ada9db22..476057b 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.cpp
+++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.cpp
@@ -34,6 +34,7 @@
 #include "platform/fonts/Font.h"
 #include "platform/fonts/shaping/ShapeResultInlineHeaders.h"
 #include "platform/fonts/shaping/ShapeResultSpacing.h"
+#include <hb.h>
 
 namespace blink {
 
@@ -271,4 +272,88 @@
     return result.release();
 }
 
+static inline float harfBuzzPositionToFloat(hb_position_t value)
+{
+    return static_cast<float>(value) / (1 << 16);
+}
+
+void ShapeResult::insertRun(PassOwnPtr<ShapeResult::RunInfo> runToInsert,
+    unsigned startGlyph, unsigned numGlyphs, hb_buffer_t* harfBuzzBuffer)
+{
+    ASSERT(numGlyphs > 0);
+    OwnPtr<ShapeResult::RunInfo> run(std::move(runToInsert));
+    ASSERT(numGlyphs == run->m_glyphData.size());
+
+    const SimpleFontData* currentFontData = run->m_fontData.get();
+    const hb_glyph_info_t* glyphInfos =
+        hb_buffer_get_glyph_infos(harfBuzzBuffer, 0);
+    const hb_glyph_position_t* glyphPositions =
+        hb_buffer_get_glyph_positions(harfBuzzBuffer, 0);
+    const unsigned startCluster =
+        HB_DIRECTION_IS_FORWARD(hb_buffer_get_direction(harfBuzzBuffer))
+        ? glyphInfos[startGlyph].cluster
+        : glyphInfos[startGlyph + numGlyphs - 1].cluster;
+
+    float totalAdvance = 0.0f;
+    FloatPoint glyphOrigin;
+    bool hasVerticalOffsets = !HB_DIRECTION_IS_HORIZONTAL(run->m_direction);
+
+    // HarfBuzz returns result in visual order, no need to flip for RTL.
+    for (unsigned i = 0; i < numGlyphs; ++i) {
+        uint16_t glyph = glyphInfos[startGlyph + i].codepoint;
+        hb_glyph_position_t pos = glyphPositions[startGlyph + i];
+
+        float offsetX = harfBuzzPositionToFloat(pos.x_offset);
+        float offsetY = -harfBuzzPositionToFloat(pos.y_offset);
+
+        // One out of x_advance and y_advance is zero, depending on
+        // whether the buffer direction is horizontal or vertical.
+        float advance = harfBuzzPositionToFloat(pos.x_advance - pos.y_advance);
+
+        // The characterIndex of one ShapeResult run is normalized to the run's
+        // startIndex and length.  TODO crbug.com/542703: Consider changing that
+        // and instead pass the whole run to hb_buffer_t each time.
+        run->m_glyphData[i].characterIndex =
+            glyphInfos[startGlyph + i].cluster - startCluster;
+
+        run->setGlyphAndPositions(i, glyph, advance, offsetX, offsetY);
+        totalAdvance += advance;
+        hasVerticalOffsets |= (offsetY != 0);
+
+        FloatRect glyphBounds = currentFontData->boundsForGlyph(glyph);
+        glyphBounds.move(glyphOrigin.x(), glyphOrigin.y());
+        m_glyphBoundingBox.unite(glyphBounds);
+        glyphOrigin += FloatSize(advance + offsetX, offsetY);
+    }
+
+    run->m_width = std::max(0.0f, totalAdvance);
+    m_width += run->m_width;
+    m_numGlyphs += numGlyphs;
+    ASSERT(m_numGlyphs >= numGlyphs);
+    m_hasVerticalOffsets |= hasVerticalOffsets;
+
+    // The runs are stored in result->m_runs in visual order. For LTR, we place
+    // the run to be inserted before the next run with a bigger character
+    // start index. For RTL, we place the run before the next run with a lower
+    // character index. Otherwise, for both directions, at the end.
+    if (HB_DIRECTION_IS_FORWARD(run->m_direction)) {
+        for (size_t pos = 0; pos < m_runs.size(); ++pos) {
+            if (m_runs.at(pos)->m_startIndex > run->m_startIndex) {
+                m_runs.insert(pos, run.release());
+                break;
+            }
+        }
+    } else {
+        for (size_t pos = 0; pos < m_runs.size(); ++pos) {
+            if (m_runs.at(pos)->m_startIndex < run->m_startIndex) {
+                m_runs.insert(pos, run.release());
+                break;
+            }
+        }
+    }
+    // If we didn't find an existing slot to place it, append.
+    if (run)
+        m_runs.append(run.release());
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.h b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.h
index 8501b8e..bb00c3e 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.h
+++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.h
@@ -40,6 +40,8 @@
 #include "wtf/RefCounted.h"
 #include "wtf/Vector.h"
 
+struct hb_buffer_t;
+
 namespace blink {
 
 class Font;
@@ -89,6 +91,8 @@
     }
 
     void applySpacing(ShapeResultSpacing&, const TextRun&);
+    void insertRun(PassOwnPtr<ShapeResult::RunInfo>, unsigned startGlyph,
+        unsigned numGlyphs, hb_buffer_t*);
 
     float m_width;
     FloatRect m_glyphBoundingBox;
diff --git a/third_party/WebKit/Source/platform/heap/HeapTest.cpp b/third_party/WebKit/Source/platform/heap/HeapTest.cpp
index adacd00..9b6cca4 100644
--- a/third_party/WebKit/Source/platform/heap/HeapTest.cpp
+++ b/third_party/WebKit/Source/platform/heap/HeapTest.cpp
@@ -6405,7 +6405,7 @@
     MutexLocker mainThreadMutexLocker(mainThreadMutex());
     OwnPtr<WebThread> workerThread = adoptPtr(Platform::current()->createThread("Test Worker Thread"));
     DestructorLockingObject* object = nullptr;
-    workerThread->getWebTaskRunner()->postTask(BLINK_FROM_HERE, threadSafeBind(workerThreadMainForCrossThreadWeakPersistentTest, AllowCrossThreadAccessWrapper<DestructorLockingObject**>(&object)));
+    workerThread->getWebTaskRunner()->postTask(BLINK_FROM_HERE, threadSafeBind(workerThreadMainForCrossThreadWeakPersistentTest, AllowCrossThreadAccess(&object)));
     parkMainThread();
 
     // Step 3: Set up a CrossThreadWeakPersistent.
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/system/executive.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/system/executive.py
index 81d9c12..fa82dd9 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/system/executive.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/system/executive.py
@@ -391,7 +391,7 @@
 
         # run_command automatically decodes to unicode() unless explicitly told not to.
         if decode_output:
-            output = output.decode(self._child_process_encoding())
+            output = output.decode(self._child_process_encoding(), errors="replace")
 
         # wait() is not threadsafe and can throw OSError due to:
         # http://bugs.python.org/issue1731717
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/android.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/android.py
index 9f5565f5..9b00de40 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/android.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/android.py
@@ -257,12 +257,10 @@
             error_handler = None
 
         result = self._executive.run_command(self.adb_command() + command,
-                                             error_handler=error_handler,
-                                             decode_output=False,
-                                             debug_logging=self._debug_logging)
+                                             error_handler=error_handler, debug_logging=self._debug_logging)
 
         # We limit the length to avoid outputting too verbose commands, such as "adb logcat".
-        self._log_debug('Run adb result: ' + result[:80].decode('ascii', errors='replace'))
+        self._log_debug('Run adb result: ' + result[:80])
         return result
 
     def get_serial(self):
@@ -315,14 +313,12 @@
     def _determine_adb_version(adb_command_path, executive, debug_logging):
         re_version = re.compile('^.*version ([\d\.]+)')
         try:
-            output = executive.run_command([adb_command_path, 'version'],
-                                           error_handler=executive.ignore_error,
-                                           decode_output=False,
+            output = executive.run_command([adb_command_path, 'version'], error_handler=executive.ignore_error,
                                            debug_logging=debug_logging)
         except OSError:
             return None
 
-        result = re_version.match(output.decode('ascii', errors='replace'))
+        result = re_version.match(output)
         if not output or not result:
             return None
 
@@ -359,10 +355,8 @@
         re_device = re.compile('^([a-zA-Z0-9_:.-]+)\tdevice$', re.MULTILINE)
 
         result = executive.run_command([AndroidCommands.adb_command_path(executive, debug_logging=self._debug_logging), 'devices'],
-                                       error_handler=executive.ignore_error,
-                                       decode_output=False,
-                                       debug_logging=self._debug_logging)
-        devices = re_device.findall(result.decode('ascii', errors='replace'))
+                                       error_handler=executive.ignore_error, debug_logging=self._debug_logging)
+        devices = re_device.findall(result)
         if not devices:
             return []
 
@@ -514,16 +508,14 @@
                 pids = self._executive.running_pids(lambda name: 'adb' in name)
                 if not pids:
                     # Apparently adb is not running, which is unusual. Running any adb command should start it.
-                    self._executive.run_command(['adb', 'devices'],
-                                                decode_output=False)
+                    self._executive.run_command(['adb', 'devices'])
                     pids = self._executive.running_pids(lambda name: 'adb' in name)
                 if not pids:
                     _log.error("The adb daemon does not appear to be running.")
                     return False
 
                 for pid in pids:
-                    self._executive.run_command(['taskset', '-p', '-c', '0', str(pid)],
-                                                decode_output=False)
+                    self._executive.run_command(['taskset', '-p', '-c', '0', str(pid)])
 
         if not result:
             _log.error('For complete Android build requirements, please see:')
@@ -742,8 +734,7 @@
 
     def _perf_version_string(self, perf_path):
         try:
-            return self._host.executive.run_command([perf_path, '--version'],
-                                                    decode_output=False)
+            return self._host.executive.run_command([perf_path, '--version'])
         except:
             return None
 
@@ -784,10 +775,9 @@
         ]
         if perfhost_path:
             perfhost_args = [perfhost_path] + perfhost_report_command + ['--call-graph', 'none']
-            perf_output = self._host.executive.run_command(perfhost_args,
-                                                           decode_output=False)
+            perf_output = self._host.executive.run_command(perfhost_args)
             # We could save off the full -g report to a file if users found that useful.
-            _log.debug(self._first_ten_lines_of_profile(perf_output).decode('ascii', errors='replace'))
+            _log.debug(self._first_ten_lines_of_profile(perf_output))
         else:
             _log.debug("""
 Failed to find perfhost_linux binary, can't process samples from the device.
diff --git a/third_party/libjingle/BUILD.gn b/third_party/libjingle/BUILD.gn
index b189c70..5b9bbe1 100644
--- a/third_party/libjingle/BUILD.gn
+++ b/third_party/libjingle/BUILD.gn
@@ -415,7 +415,6 @@
       "//third_party/webrtc",
       "//third_party/webrtc/modules/media_file",
       "//third_party/webrtc/modules/video_capture",
-      "//third_party/webrtc/modules/video_render",
       "//third_party/webrtc/system_wrappers",
       "//third_party/webrtc/voice_engine",
     ]
diff --git a/third_party/libjingle/README.chromium b/third_party/libjingle/README.chromium
index b2e6977..a7accdf 100644
--- a/third_party/libjingle/README.chromium
+++ b/third_party/libjingle/README.chromium
@@ -1,7 +1,7 @@
 Name: libjingle
 URL: http://www.webrtc.org
 Version: unknown
-Revision: 12501
+Revision: 12534
 License: BSD
 License File: source/talk/COPYING
 Security Critical: yes
diff --git a/third_party/libjingle/libjingle.gyp b/third_party/libjingle/libjingle.gyp
index d146e71..20403df 100644
--- a/third_party/libjingle/libjingle.gyp
+++ b/third_party/libjingle/libjingle.gyp
@@ -365,7 +365,6 @@
             '<(DEPTH)/third_party/usrsctp/usrsctp.gyp:usrsctplib',
             '<(DEPTH)/third_party/webrtc/modules/modules.gyp:media_file',
             '<(DEPTH)/third_party/webrtc/modules/modules.gyp:video_capture',
-            '<(DEPTH)/third_party/webrtc/modules/modules.gyp:video_render',
             '<(DEPTH)/third_party/webrtc/voice_engine/voice_engine.gyp:voice_engine',
             '<(DEPTH)/third_party/webrtc/webrtc.gyp:webrtc',
             'libjingle',
diff --git a/third_party/libjingle/libjingle_nacl.gyp b/third_party/libjingle/libjingle_nacl.gyp
index 46129c8..99dd667 100644
--- a/third_party/libjingle/libjingle_nacl.gyp
+++ b/third_party/libjingle/libjingle_nacl.gyp
@@ -138,6 +138,7 @@
         '<(webrtc_base)/network.h',
         '<(webrtc_base)/networkmonitor.cc',
         '<(webrtc_base)/networkmonitor.h',
+        '<(webrtc_base)/nullsocketserver.cc',
         '<(webrtc_base)/nullsocketserver.h',
         '<(webrtc_base)/openssladapter.cc',
         '<(webrtc_base)/openssldigest.cc',
diff --git a/third_party/qcms/README.chromium b/third_party/qcms/README.chromium
index 98653d6..a62e37d 100644
--- a/third_party/qcms/README.chromium
+++ b/third_party/qcms/README.chromium
@@ -151,6 +151,8 @@
    - https://code.google.com/p/chromium/issues/detail?id=580917
  - Fix build_output_lut to return correct data for parametric curves
    - https://bugs.chromium.org/p/chromium/issues/detail?id=600338
+ - Make build_output_lut output 4096 points for parametric curves
+   - https://bugs.chromium.org/p/chromium/issues/detail?id=600338
 
 For the Chromium changes, since the import, in a patch format run:
   git diff b8456f38 src
diff --git a/third_party/qcms/src/tests/qcms_test_output_trc.c b/third_party/qcms/src/tests/qcms_test_output_trc.c
index 9f95a3b..771033f7 100644
--- a/third_party/qcms/src/tests/qcms_test_output_trc.c
+++ b/third_party/qcms/src/tests/qcms_test_output_trc.c
@@ -40,7 +40,7 @@
     }
 
     *size = qcms_transform_get_output_trc_rgba(transform, target, QCMS_TRC_USHORT, NULL);
-    assert(*size == 256);
+    assert(*size >= 256);
 
     *table = malloc(*size * sizeof(uint16_t) * 4);
     qcms_transform_get_output_trc_rgba(transform, target, QCMS_TRC_USHORT, *table);
@@ -75,7 +75,7 @@
     }
 
     *size = qcms_transform_get_input_trc_rgba(transform, source, QCMS_TRC_USHORT, NULL);
-    assert(*size == 256);
+    assert(*size >= 256);
 
     *table = calloc(*size, sizeof(uint16_t) * 4);
     qcms_transform_get_input_trc_rgba(transform, source, QCMS_TRC_USHORT, *table);
@@ -96,7 +96,7 @@
 {
     qcms_profile *profile;
     uint16_t *gamma_table_out;
-    size_t gamma_table_size;
+    size_t output_size;
     size_t i;
 
     printf("Test qcms output gamma curve table integrity.\n");
@@ -109,13 +109,13 @@
     // Create profiles and transforms, get table and then free resources to make sure none
     // of the internal tables are initialized by previous calls.
     gamma_table_out = NULL;
-    gamma_table_size = 0;
-    if (get_output_gamma_table(in_path, &gamma_table_out, &gamma_table_size) != 0) {
+    output_size = 0;
+    if (get_output_gamma_table(in_path, &gamma_table_out, &output_size) != 0) {
         fprintf(stderr, "Unable to extract output gamma table\n");
         return EXIT_FAILURE;
     }
 
-    printf("LUT size = %zu\n", gamma_table_size);
+    printf("Output gamma LUT size = %zu\n", output_size);
 
     profile = qcms_profile_from_path(in_path);
     if (!profile) {
@@ -127,16 +127,17 @@
     // Check only for red curve for now.
     if (profile->redTRC->type == PARAMETRIC_CURVE_TYPE) {
         int type = - (int)(profile->redTRC->count + 1);
-        FILE *gamma_file;
         uint16_t *gamma_table_in = NULL;
-        uint16_t *p_table_out, *p_table_in;
-        char file_name[256] = {0,};
         size_t input_size = 0;
+        float scale_factor;
+        FILE *output_file;
+        char output_file_name[1024];
+        long int time_stamp = (long int)time(NULL);
 
         printf("Detected parametric curve type = %d\n", profile->redTRC->count);
 
-        sprintf(file_name, "qcms-test-%ld-parametric-gamma-%s.csv", (long int)time(NULL), profile->description);
-        printf("Writing input and output gamma tables to %s\n", file_name);
+        sprintf(output_file_name, "qcms-test-%ld-parametric-gamma-output-%s.csv", time_stamp, profile->description);
+        printf("Writing output gamma tables to %s\n", output_file_name);
 
         printf("gamma = %.6f, a = %.6f, b = %.6f, c = %.6f, d = %.6f, e = %.6f, f = %.6f\n",
                 profile->redTRC->parameter[0], profile->redTRC->parameter[1], profile->redTRC->parameter[2],
@@ -144,44 +145,44 @@
                 profile->redTRC->parameter[6]);
 
         // Write output to stdout and tables into a csv file.
-        gamma_file = fopen(file_name, "w");
-        fprintf(gamma_file, "Parametric gamma values for %s\n", profile->description);
-        fprintf(gamma_file, "gamma, a, b, c, d, e, f\n");
-        fprintf(gamma_file, "%.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f\n",
+        output_file = fopen(output_file_name, "w");
+        fprintf(output_file, "Parametric gamma values for %s\n", profile->description);
+        fprintf(output_file, "gamma, a, b, c, d, e, f\n");
+        fprintf(output_file, "%.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f\n",
                 profile->redTRC->parameter[0], profile->redTRC->parameter[1], profile->redTRC->parameter[2],
                 profile->redTRC->parameter[3], profile->redTRC->parameter[4], profile->redTRC->parameter[5],
                 profile->redTRC->parameter[6]);
 
         get_input_gamma_table(in_path, &gamma_table_in, &input_size);
-        assert(input_size == gamma_table_size);
         if (!gamma_table_in) {
             fprintf(stderr, "Unable to compute input trc. Aborting\n");
-            fclose(gamma_file);
+            fclose(output_file);
             qcms_profile_release(profile);
             free(gamma_table_out);
             return EXIT_FAILURE;
         }
 
-        fprintf(gamma_file, "\n\nInput gamma, Output gamma, LCMS Output gamma, Output gamma error\n");
+        scale_factor = (float)(output_size - 1) / (input_size - 1);
 
-        p_table_out = gamma_table_out;
-        p_table_in = gamma_table_in;
+        fprintf(output_file, "\nInput curve size: %zu\nOutput curve size: %zu\n", input_size, output_size);
+        fprintf(output_file, "\n\nInput gamma, Output gamma, LCMS Output gamma, Output gamma error\n");
 
-        for (i = 0; i < gamma_table_size; ++i) {
-            float p = i / (gamma_table_size * 1.0);
-            float reference_out = clamp_float(evaluate_parametric_curve(type, profile->redTRC->parameter, p));
-            float actual_out = *p_table_out * inverse65535;
-            float error_out = fabs(actual_out - reference_out);
-            float input = *p_table_in * inverse65535;
+        for (i = 0; i < input_size; ++i) {
+            float input = gamma_table_in[i * 4] * inverse65535;
+            size_t out_index = (size_t)floor(i * scale_factor + 0.5);
+            float p = out_index / (float)(output_size - 1);
+            float reference = clamp_float(evaluate_parametric_curve(type, profile->redTRC->parameter, p));
+            float actual = gamma_table_out[out_index * 4] * inverse65535;
+            float difference = fabs(actual - reference);
 
-            fprintf(gamma_file, "%.6f, %.6f, %6f, %6f\n",input, actual_out, reference_out, error_out);
-
-            p_table_out += 4; // Skip other channels.
-            p_table_in += 4; // Skip other channels.
+            fprintf(output_file, "%.6f, %.6f, %6f, %6f\n", input, actual, reference, difference);
         }
 
+        fprintf(output_file, "\nNote: the output curves we down sampled by a factor of %zu / %zu\n",
+                output_size, input_size);
+
+        fclose(output_file);
         free(gamma_table_in);
-        fclose(gamma_file);
     }
 
     qcms_profile_release(profile);
diff --git a/third_party/qcms/src/transform_util.c b/third_party/qcms/src/transform_util.c
index 3d84716e..3b2dcef7 100644
--- a/third_party/qcms/src/transform_util.c
+++ b/third_party/qcms/src/transform_util.c
@@ -601,7 +601,7 @@
                 uint16_t i;
                 uint16_t *output = malloc(sizeof(uint16_t)*256);
                 uint16_t *inverted;
-                int inverted_size = 256;
+                int inverted_size = 4096;
 
                 if (!output) {
                         *output_gamma_lut = NULL;
@@ -618,9 +618,6 @@
                 //     measurement or data, however it is what lcms uses.
                 //     the maximum number we would need is 65535 because that's the
                 //     accuracy used for computing the pre cache table
-                if (inverted_size < 256)
-                        inverted_size = 256;
-
                 inverted = invert_lut(output, 256, inverted_size);
                 if (!inverted)
                         return;
diff --git a/tools/android/loading/cloud/frontend/clovis_frontend.py b/tools/android/loading/cloud/frontend/clovis_frontend.py
index ffef8be..42b7b09 100644
--- a/tools/android/loading/cloud/frontend/clovis_frontend.py
+++ b/tools/android/loading/cloud/frontend/clovis_frontend.py
@@ -14,6 +14,7 @@
 
 from common.clovis_task import ClovisTask
 import common.google_instance_helper
+import email_helper
 from memory_logs import MemoryLogs
 
 
@@ -33,7 +34,7 @@
       'log.html', body=message, log=memory_logs.Flush().split('\n'))
 
 
-def PollWorkers(tag, start_time, timeout_hours):
+def PollWorkers(tag, start_time, timeout_hours, email_address, task_url):
   """Checks if there are workers associated with tag, by polling the instance
   group. When all workers are finished, the instance group and the instance
   template are destroyed.
@@ -46,10 +47,12 @@
     start_time (float): Time when the polling started, as returned by
                         time.time().
     timeout_hours (int): Timeout after which workers are terminated.
+    email_address (str): Email address to notify when the task is complete.
+    task_url (str): URL where the results of the task can be found.
   """
   if (time.time() - start_time) > (3600 * timeout_hours):
     clovis_logger.error('Worker timeout for tag %s, shuting down.' % tag)
-    deferred.defer(DeleteInstanceGroup, tag)
+    Finalize(tag, email_address, 'TIMEOUT', task_url)
     return
 
   clovis_logger.info('Polling workers for tag: ' + tag)
@@ -60,10 +63,26 @@
   if live_instance_count > 0 or live_instance_count == -1:
     clovis_logger.info('Retry later, instances still alive for tag: ' + tag)
     poll_interval_minutes = 10
-    deferred.defer(PollWorkers, tag, start_time,
+    deferred.defer(PollWorkers, tag, start_time, email_address, task_url,
                    _countdown=(60 * poll_interval_minutes))
     return
 
+  Finalize(tag, email_address, 'SUCCESS', task_url)
+
+
+def Finalize(tag, email_address, status, task_url):
+  """Cleans up the remaining ComputeEngine resources and notifies the user.
+
+  Args:
+    tag (str): Tag of the task to finalize.
+    email_address (str): Email address of the user to be notified.
+    status (str): Status of the task, indicating the success or the cause of
+                  failure.
+    task_url (str): URL where the results of the task can be found.
+  """
+  email_helper.SendEmailTaskComplete(
+      to_address=email_address, tag=tag, status=status, task_url=task_url,
+      logger=clovis_logger)
   clovis_logger.info('Scheduling instance group destruction for tag: ' + tag)
   deferred.defer(DeleteInstanceGroup, tag)
 
@@ -142,7 +161,11 @@
 
   # Split the task in smaller tasks.
   sub_tasks = []
+  task_url = None
   if task.Action() == 'trace':
+    bucket = task.BackendParams().get('storage_bucket')
+    if bucket:
+      task_url = 'https://console.cloud.google.com/storage/' + bucket
     sub_tasks = SplitTraceTask(task)
   else:
     error_string = 'Unsupported action: %s.' % task.Action()
@@ -160,10 +183,14 @@
   clovis_logger.info('Creating worker polling task.')
   first_poll_delay_minutes = 10
   timeout_hours = task.BackendParams().get('timeout_hours', 5)
-  deferred.defer(PollWorkers, task_tag, time.time(), timeout_hours,
-                 _countdown=(60 * first_poll_delay_minutes))
+  user_email = email_helper.GetUserEmail()
+  deferred.defer(PollWorkers, task_tag, time.time(), timeout_hours, user_email,
+                 task_url, _countdown=(60 * first_poll_delay_minutes))
 
-  return Render('Success', memory_logs)
+  return Render(flask.Markup(
+      'Success!<br>Your task %s has started.<br>'
+      'You will be notified at %s when completed.') % (task_tag, user_email),
+      memory_logs)
 
 
 def SplitTraceTask(task):
diff --git a/tools/android/loading/cloud/frontend/email_helper.py b/tools/android/loading/cloud/frontend/email_helper.py
new file mode 100644
index 0000000..dd82ee7
--- /dev/null
+++ b/tools/android/loading/cloud/frontend/email_helper.py
@@ -0,0 +1,42 @@
+# 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.
+
+from google.appengine.api import (mail, users)
+
+
+def GetUserEmail():
+  """Returns the email address of the user currently making the request or None.
+  """
+  user = users.get_current_user()
+  if user:
+    return user.email()
+  return None
+
+
+def SendEmailTaskComplete(to_address, tag, status, task_url, logger):
+  """Sends an email to to_address notifying that the task identified by tag is
+  complete.
+
+  Args:
+    to_address (str): The email address to notify.
+    tag (str): The tag of the task.
+    status (str): Status of the task.
+    task_url (str): URL where the results of the task can be found.
+    logger (logging.logger): Used for logging.
+  """
+  if not to_address:
+    logger.error('No email address to notify for task ' + tag)
+    return
+
+  logger.info('Notify task %s complete to %s.' % (tag, to_address))
+  # The sender address must be in the "Email API authorized senders", configured
+  # in the Application Settings of AppEngine.
+  sender_address = 'clovis-noreply@google.com'
+  subject = 'Task %s complete' % tag
+  body = 'Your Clovis task %s is now complete with status: %s.' % (tag, status)
+  if task_url:
+    body += '\nCheck the results at ' + task_url
+  mail.send_mail(sender=sender_address, to=to_address, subject=subject,
+                 body=body)
+
diff --git a/tools/android/loading/controller.py b/tools/android/loading/controller.py
index d8c20e01..8a2d4a6 100644
--- a/tools/android/loading/controller.py
+++ b/tools/android/loading/controller.py
@@ -324,6 +324,8 @@
        child processes used to run Chrome and XVFB."""
     chrome_cmd = [OPTIONS.local_binary]
     chrome_cmd.extend(self._GetChromeArguments())
+    # Force use of simple cache.
+    chrome_cmd.append('--use-simple-cache-backend=on')
     chrome_cmd.append('--user-data-dir=%s' % self._profile_dir)
     chrome_cmd.extend(['--enable-logging=stderr', '--v=1'])
     # Navigates to about:blank for couples of reasons:
diff --git a/tools/android/loading/prefetch_view.py b/tools/android/loading/prefetch_view.py
index 0df9025b..cbd882a 100644
--- a/tools/android/loading/prefetch_view.py
+++ b/tools/android/loading/prefetch_view.py
@@ -52,7 +52,7 @@
     if trace is None:
       return
     requests = trace.request_track.GetEvents()
-    critical_requests_ids = user_lens.CriticalRequests()
+    critical_requests_ids = user_lens.CriticalRequestIds()
     self.postload_msec = user_lens.PostloadTimeMsec()
     self.graph = dependency_graph.RequestDependencyGraph(
         requests, dependencies_lens, node_class=RequestNode)
diff --git a/tools/android/loading/request_track.py b/tools/android/loading/request_track.py
index b4e3a15..8bd62da 100644
--- a/tools/android/loading/request_track.py
+++ b/tools/android/loading/request_track.py
@@ -12,6 +12,7 @@
 import copy
 import datetime
 import email.utils
+import hashlib
 import json
 import logging
 import re
@@ -213,6 +214,12 @@
       return None
     return self.start_msec + self.timing.LargestOffset()
 
+  @property
+  def fingerprint(self):
+    h = hashlib.sha256()
+    h.update(self.url)
+    return h.hexdigest()[:10]
+
   def _TimestampOffsetFromStartMs(self, timestamp):
     assert self.timing.request_time != -1
     request_time = self.timing.request_time
diff --git a/tools/android/loading/sandwich.py b/tools/android/loading/sandwich.py
index 6dda5d0..d7ec1a1a 100755
--- a/tools/android/loading/sandwich.py
+++ b/tools/android/loading/sandwich.py
@@ -44,6 +44,9 @@
 # Use options layer to access constants.
 OPTIONS = options.OPTIONS
 
+_SPEED_INDEX_MEASUREMENT = 'speed-index'
+_MEMORY_MEASUREMENT = 'memory'
+
 
 def _ArgumentParser():
   """Build a command line argument's parser."""
@@ -179,6 +182,9 @@
                        parents=[common_job_parser, task_parser],
                        help='Run all steps using the task manager '
                             'infrastructure.')
+  run_all.add_argument('-m', '--measure', default=[], dest='optional_measures',
+                       choices=[_SPEED_INDEX_MEASUREMENT, _MEMORY_MEASUREMENT],
+                       nargs='+', help='Enable optional measurements.')
   run_all.add_argument('-g', '--gen-full', action='store_true',
                        help='Generate the full graph with all possible'
                             'benchmarks.')
@@ -281,31 +287,37 @@
   builder = sandwich_task_builder.SandwichTaskBuilder(
       output_directory=args.output,
       android_device=android_device,
-      job_path=args.job,
-      url_repeat=args.url_repeat)
+      job_path=args.job)
   if args.wpr_archive_path:
     builder.OverridePathToWprArchive(args.wpr_archive_path)
   else:
     builder.PopulateWprRecordingTask()
   builder.PopulateCommonPipelines()
 
-  runner_transformer_name = 'no-network-emulation'
-  runner_transformer = lambda arg: None
+  def MainTransformer(runner):
+    runner.record_video = _SPEED_INDEX_MEASUREMENT in args.optional_measures
+    runner.record_memory_dumps = _MEMORY_MEASUREMENT in args.optional_measures
+    runner.job_repeat = args.url_repeat
+
+  transformer_list_name = 'no-network-emulation'
   builder.PopulateLoadBenchmark(sandwich_misc.EMPTY_CACHE_DISCOVERER,
-                                runner_transformer_name, runner_transformer)
+                                transformer_list_name,
+                                transformer_list=[MainTransformer])
   builder.PopulateLoadBenchmark(sandwich_misc.FULL_CACHE_DISCOVERER,
-                                runner_transformer_name, runner_transformer)
+                                transformer_list_name,
+                                transformer_list=[MainTransformer])
 
   if args.gen_full:
-    for subresource_discoverer in sandwich_misc.SUBRESOURCE_DISCOVERERS:
-      if subresource_discoverer == sandwich_misc.FULL_CACHE_DISCOVERER:
-        continue
-      for network_condition in ['Regular4G', 'Regular3G', 'Regular2G']:
-        runner_transformer_name = network_condition.lower()
-        runner_transformer = sandwich_task_builder.NetworkSimulationTransformer(
-            network_condition)
-        builder.PopulateLoadBenchmark(
-            subresource_discoverer, runner_transformer_name, runner_transformer)
+    for network_condition in ['Regular4G', 'Regular3G', 'Regular2G']:
+      transformer_list_name = network_condition.lower()
+      network_transformer = \
+          sandwich_task_builder.NetworkSimulationTransformer(network_condition)
+      transformer_list = [MainTransformer, network_transformer]
+      for subresource_discoverer in sandwich_misc.SUBRESOURCE_DISCOVERERS:
+        if subresource_discoverer == sandwich_misc.FULL_CACHE_DISCOVERER:
+          continue
+        builder.PopulateLoadBenchmark(subresource_discoverer,
+            transformer_list_name, transformer_list)
 
   return task_manager.ExecuteWithCommandLine(
       args, builder.tasks.values(), builder.default_final_tasks)
diff --git a/tools/android/loading/sandwich_metrics.py b/tools/android/loading/sandwich_metrics.py
index 1324b75..339cf72 100644
--- a/tools/android/loading/sandwich_metrics.py
+++ b/tools/android/loading/sandwich_metrics.py
@@ -43,6 +43,8 @@
     'net_emul.upload',
     'net_emul.latency']
 
+_UNAVAILABLE_CSV_VALUE = 'unavailable'
+
 _TRACKED_EVENT_NAMES = set(['requestStart', 'loadEventStart', 'loadEventEnd'])
 
 # Points of a completeness record.
@@ -81,6 +83,7 @@
   Returns:
     List of memory dump events.
   """
+  assert sandwich_runner.MEMORY_DUMP_CATEGORY in tracing_track.Categories()
   browser_pid = _GetBrowserPID(tracing_track)
   browser_dumps_events = []
   for event in tracing_track.GetEvents():
@@ -130,8 +133,8 @@
   return tracked_events
 
 
-def _ExtractMetricsFromLoadingTrace(loading_trace):
-  """Pulls all the metrics from a given trace.
+def _ExtractDefaultMetrics(loading_trace):
+  """Extracts all the default metrics from a given trace.
 
   Args:
     loading_trace: loading_trace_module.LoadingTrace.
@@ -139,15 +142,32 @@
   Returns:
     Dictionary with all trace extracted fields set.
   """
-  assert all(
-      cat in loading_trace.tracing_track.Categories()
-      for cat in sandwich_runner.ADDITIONAL_CATEGORIES), (
-          'This trace was not generated with the required set of categories '
-          'to be processed by this script.')
-  browser_dump_events = _GetBrowserDumpEvents(loading_trace.tracing_track)
   web_page_tracked_events = _GetWebPageTrackedEvents(
       loading_trace.tracing_track)
+  return {
+    'total_load': (web_page_tracked_events['loadEventEnd'].start_msec -
+                   web_page_tracked_events['requestStart'].start_msec),
+    'js_onload_event': (web_page_tracked_events['loadEventEnd'].start_msec -
+                        web_page_tracked_events['loadEventStart'].start_msec)
+  }
 
+
+def _ExtractMemoryMetrics(loading_trace):
+  """Extracts all the memory metrics from a given trace.
+
+  Args:
+    loading_trace: loading_trace_module.LoadingTrace.
+
+  Returns:
+    Dictionary with all trace extracted fields set.
+  """
+  if (sandwich_runner.MEMORY_DUMP_CATEGORY not in
+          loading_trace.tracing_track.Categories()):
+    return {
+      'browser_malloc_avg': _UNAVAILABLE_CSV_VALUE,
+      'browser_malloc_max': _UNAVAILABLE_CSV_VALUE
+    }
+  browser_dump_events = _GetBrowserDumpEvents(loading_trace.tracing_track)
   browser_malloc_sum = 0
   browser_malloc_max = 0
   for dump_event in browser_dump_events:
@@ -156,12 +176,7 @@
     size = int(attr['value'], 16)
     browser_malloc_sum += size
     browser_malloc_max = max(browser_malloc_max, size)
-
   return {
-    'total_load': (web_page_tracked_events['loadEventEnd'].start_msec -
-                   web_page_tracked_events['requestStart'].start_msec),
-    'js_onload_event': (web_page_tracked_events['loadEventEnd'].start_msec -
-                        web_page_tracked_events['loadEventStart'].start_msec),
     'browser_malloc_avg': browser_malloc_sum / float(len(browser_dump_events)),
     'browser_malloc_max': browser_malloc_max
   }
@@ -239,14 +254,15 @@
   logging.info('processing trace \'%s\'' % trace_path)
   loading_trace = loading_trace_module.LoadingTrace.FromJsonFile(trace_path)
   run_metrics = {'url': loading_trace.url}
-  run_metrics.update(_ExtractMetricsFromLoadingTrace(loading_trace))
+  run_metrics.update(_ExtractDefaultMetrics(loading_trace))
+  run_metrics.update(_ExtractMemoryMetrics(loading_trace))
   video_path = os.path.join(run_directory_path, 'video.mp4')
   if os.path.isfile(video_path):
     logging.info('processing speed-index video \'%s\'' % video_path)
     completeness_record = _ExtractCompletenessRecordFromVideo(video_path)
     run_metrics['speed_index'] = ComputeSpeedIndex(completeness_record)
   else:
-    run_metrics['speed_index'] = 'disabled'
+    run_metrics['speed_index'] = _UNAVAILABLE_CSV_VALUE
   for key, value in loading_trace.metadata['network_emulation'].iteritems():
     run_metrics['net_emul.' + key] = value
   return run_metrics
diff --git a/tools/android/loading/sandwich_metrics_unittest.py b/tools/android/loading/sandwich_metrics_unittest.py
index 73c8f3e..e7553bc3 100644
--- a/tools/android/loading/sandwich_metrics_unittest.py
+++ b/tools/android/loading/sandwich_metrics_unittest.py
@@ -19,7 +19,7 @@
 
 
 _BLINK_CAT = 'blink.user_timing'
-_MEM_CAT = 'disabled-by-default-memory-infra'
+_MEM_CAT = sandwich_runner.MEMORY_DUMP_CATEGORY
 _START='requestStart'
 _LOADS='loadEventStart'
 _LOADE='loadEventEnd'
@@ -48,7 +48,7 @@
   return tracing.TracingTrack.FromJsonDict({
       'events': events,
       'categories': (tracing.INITIAL_CATEGORIES +
-          sandwich_runner.ADDITIONAL_CATEGORIES)})
+          (sandwich_runner.MEMORY_DUMP_CATEGORY,))})
 
 
 def LoadingTrace(events):
@@ -107,8 +107,6 @@
         {'pid': 354, 'ts': 11000, 'cat': 'whatever0', 'ph': 'R'},
         {'pid': 672, 'ts': 12000, 'cat': _MEM_CAT, 'ph': 'v', 'name': NAME}]
 
-    self.assertTrue(_MEM_CAT in sandwich_runner.ADDITIONAL_CATEGORIES)
-
     bump_events = RunHelper(TRACE_EVENTS, 123)
     self.assertEquals(2, len(bump_events))
     self.assertEquals(5, bump_events[0].start_msec)
@@ -187,12 +185,17 @@
     self.assertEquals(17, trace_events['loadEventStart'].start_msec)
     self.assertEquals(19, trace_events['loadEventEnd'].start_msec)
 
-  def testPullMetricsFromLoadingTrace(self):
-    metrics = puller._ExtractMetricsFromLoadingTrace(LoadingTrace(
+  def testExtractDefaultMetrics(self):
+    metrics = puller._ExtractDefaultMetrics(LoadingTrace(
         _MINIMALIST_TRACE_EVENTS))
-    self.assertEquals(4, len(metrics))
+    self.assertEquals(2, len(metrics))
     self.assertEquals(20, metrics['total_load'])
     self.assertEquals(5, metrics['js_onload_event'])
+
+  def testExtractMemoryMetrics(self):
+    metrics = puller._ExtractMemoryMetrics(LoadingTrace(
+        _MINIMALIST_TRACE_EVENTS))
+    self.assertEquals(2, len(metrics))
     self.assertEquals(30971, metrics['browser_malloc_avg'])
     self.assertEquals(55044, metrics['browser_malloc_max'])
 
diff --git a/tools/android/loading/sandwich_runner.py b/tools/android/loading/sandwich_runner.py
index 3a56b59..3dc0415 100644
--- a/tools/android/loading/sandwich_runner.py
+++ b/tools/android/loading/sandwich_runner.py
@@ -26,9 +26,8 @@
 TRACE_FILENAME = 'trace.json'
 VIDEO_FILENAME = 'video.mp4'
 
-# List of selected trace event categories when running chrome.
-ADDITIONAL_CATEGORIES = (
-    'disabled-by-default-memory-infra',)  # Used by _GetBrowserDumpEvents()
+# Memory dump category used to get memory metrics.
+MEMORY_DUMP_CATEGORY = 'disabled-by-default-memory-infra'
 
 _JOB_SEARCH_PATH = 'sandwich_jobs'
 
@@ -124,6 +123,9 @@
     # Configures whether to record speed-index video.
     self.record_video = False
 
+    # Configures whether to record memory dumps.
+    self.record_memory_dumps = False
+
     # Path to the WPR archive to load or save. Is str or None.
     self.wpr_archive_path = None
 
@@ -189,13 +191,17 @@
         os.makedirs(run_path)
     self._chrome_ctl.SetNetworkEmulation(
         self._GetEmulatorNetworkCondition('browser'))
+    additional_categories = []
+    if self.record_memory_dumps:
+      additional_categories = [MEMORY_DUMP_CATEGORY]
     # TODO(gabadie): add a way to avoid recording a trace.
     with self._chrome_ctl.Open() as connection:
       if clear_cache:
         connection.ClearCache()
       if run_path is not None and self.record_video:
         device = self._chrome_ctl.GetDevice()
-        assert device, 'Can only record video on a remote device.'
+        if device is None:
+          raise RuntimeError('Can only record video on a remote device.')
         video_recording_path = os.path.join(run_path, VIDEO_FILENAME)
         with device_setup.RemoteSpeedIndexRecorder(device, connection,
                                                    video_recording_path):
@@ -203,14 +209,14 @@
               url=url,
               connection=connection,
               chrome_metadata=self._chrome_ctl.ChromeMetadata(),
-              additional_categories=ADDITIONAL_CATEGORIES,
+              additional_categories=additional_categories,
               timeout_seconds=_DEVTOOLS_TIMEOUT)
       else:
         trace = loading_trace.LoadingTrace.RecordUrlNavigation(
             url=url,
             connection=connection,
             chrome_metadata=self._chrome_ctl.ChromeMetadata(),
-            additional_categories=ADDITIONAL_CATEGORIES,
+            additional_categories=additional_categories,
             timeout_seconds=_DEVTOOLS_TIMEOUT)
     if run_path is not None:
       trace_path = os.path.join(run_path, TRACE_FILENAME)
diff --git a/tools/android/loading/sandwich_task_builder.py b/tools/android/loading/sandwich_task_builder.py
index 954c67e..ea763ecb 100644
--- a/tools/android/loading/sandwich_task_builder.py
+++ b/tools/android/loading/sandwich_task_builder.py
@@ -37,7 +37,7 @@
   """A builder for a graph of tasks, each prepares or invokes a SandwichRunner.
   """
 
-  def __init__(self, output_directory, android_device, job_path, url_repeat):
+  def __init__(self, output_directory, android_device, job_path):
     """Constructor.
 
     Args:
@@ -45,13 +45,10 @@
       android_device: The android DeviceUtils to run sandwich on or None to run
         it locally.
       job_path: Path of the sandwich's job.
-      url_repeat: Non null integer controlling how many times the URLs should be
-        repeated in the benchmarks.
     """
     task_manager.Builder.__init__(self, output_directory)
     self._android_device = android_device
     self._job_path = job_path
-    self._url_repeat = url_repeat
     self._default_final_tasks = []
 
     self._original_wpr_task = None
@@ -159,20 +156,20 @@
     return ValidateReferenceCache
 
   def PopulateLoadBenchmark(self, subresource_discoverer,
-                            runner_transformer_name, runner_transformer):
+                            transformer_list_name, transformer_list):
     """Populate benchmarking tasks from its setup tasks.
 
     Args:
       subresource_discoverer: Name of a subresources discoverer.
-      runner_transformer: A function that takes an instance of SandwichRunner as
-          parameter, would be applied immediately before SandwichRunner.Run().
-      runner_transformer_name: Name of the runner transformer used to generate
-          task names.
-      benchmark_name: The benchmark's name for that runner modifier.
+      transformer_list_name: A string describing the transformers, will be used
+          in Task names (prefer names without spaces and special characters).
+      transformer_list: An ordered list of function that takes an instance of
+          SandwichRunner as parameter, would be applied immediately before
+          SandwichRunner.Run() in the given order.
 
     Here is the full dependency of the added tree for the returned task:
-    <runner_transformer_name>/<subresource_discoverer>-metrics.csv
-      depends on: <runner_transformer_name>/<subresource_discoverer>-run/
+    <transformer_list_name>/<subresource_discoverer>-metrics.csv
+      depends on: <transformer_list_name>/<subresource_discoverer>-run/
         depends on: common/<subresource_discoverer>-cache.zip
           depends on: some tasks saved by PopulateCommonPipelines()
           depends on: common/<subresource_discoverer>-setup.json
@@ -180,12 +177,12 @@
 
     Returns:
       task_manager.Task for
-          <runner_transformer_name>/<subresource_discoverer>-metrics.csv
+          <transformer_list_name>/<subresource_discoverer>-metrics.csv
     """
     assert subresource_discoverer in sandwich_misc.SUBRESOURCE_DISCOVERERS
     assert 'common' not in sandwich_misc.SUBRESOURCE_DISCOVERERS
     shared_task_prefix = os.path.join('common', subresource_discoverer)
-    task_prefix = os.path.join(runner_transformer_name, subresource_discoverer)
+    task_prefix = os.path.join(transformer_list_name, subresource_discoverer)
 
     @self.RegisterTask(shared_task_prefix + '-setup.json', merge=True,
                        dependencies=[self._subresources_for_urls_task])
@@ -221,9 +218,8 @@
                        dependencies=[BuildBenchmarkCacheArchive])
     def RunBenchmark():
       runner = self._CreateSandwichRunner()
-      # runner.record_video = True
-      runner.job_repeat = self._url_repeat
-      runner_transformer(runner)
+      for transformer in transformer_list:
+        transformer(runner)
       runner.wpr_archive_path = self._patched_wpr_task.path
       runner.wpr_out_log_path = os.path.join(RunBenchmark.path, 'wpr.log')
       runner.cache_archive_path = BuildBenchmarkCacheArchive.path
diff --git a/tools/android/loading/test_utils.py b/tools/android/loading/test_utils.py
index 8f61969..10385b5 100644
--- a/tools/android/loading/test_utils.py
+++ b/tools/android/loading/test_utils.py
@@ -221,7 +221,7 @@
     return response
 
 
-class MockUserSatisfiedLens(user_satisfied_lens._UserSatisfiedLens):
+class MockUserSatisfiedLens(user_satisfied_lens._FirstEventLens):
   def _CalculateTimes(self, _):
     self._satisfied_msec = float('inf')
     self._event_msec = float('inf')
diff --git a/tools/android/loading/tracing.py b/tools/android/loading/tracing.py
index 068c5b6b..55009a63 100644
--- a/tools/android/loading/tracing.py
+++ b/tools/android/loading/tracing.py
@@ -92,10 +92,26 @@
 
   def GetMatchingMainFrameEvents(self, category, name):
     """Gets events matching |category| and |name| that occur in the main frame.
-    Assumes that the events in question have a 'frame' key in their |args|."""
+
+    Events without a 'frame' key in their |args| are discarded.
+    """
     matching_events = self.GetMatchingEvents(category, name)
     return [e for e in matching_events
-        if e.args['frame'] == self._GetMainFrameID()]
+        if 'frame' in e.args and e.args['frame'] == self.GetMainFrameID()]
+
+  def GetMainFrameID(self):
+    """Returns the main frame ID."""
+    if not self._main_frame_id:
+      navigation_start_events = [e for e in self.GetEvents()
+          if e.Matches('blink.user_timing', 'navigationStart')]
+      first_event = min(navigation_start_events, key=lambda e: e.start_msec)
+      self._main_frame_id = first_event.args['frame']
+
+    return self._main_frame_id
+
+  def SetMainFrameID(self, frame_id):
+    """Set the main frame ID. Normally this is used only for testing."""
+    self._main_frame_id = frame_id
 
   def EventsAt(self, msec):
     """Gets events active at a timestamp.
@@ -197,16 +213,6 @@
         return event
     return None
 
-  def _GetMainFrameID(self):
-    """Returns the main frame ID."""
-    if not self._main_frame_id:
-      navigation_start_events = [e for e in self.GetEvents()
-          if e.Matches('blink.user_timing', 'navigationStart')]
-      first_event = min(navigation_start_events, key=lambda e: e.start_msec)
-      self._main_frame_id = first_event.args['frame']
-
-    return self._main_frame_id
-
   def _IndexEvents(self, strict=False):
     if self._interval_tree:
       return
diff --git a/tools/android/loading/tracing_unittest.py b/tools/android/loading/tracing_unittest.py
index cce5809..95acef8 100644
--- a/tools/android/loading/tracing_unittest.py
+++ b/tools/android/loading/tracing_unittest.py
@@ -309,7 +309,7 @@
          'args': {'frame': _MAIN_FRAME_ID}},
         ]
     self._HandleEvents(events)
-    self.assertEquals(_MAIN_FRAME_ID, self.track._GetMainFrameID())
+    self.assertEquals(_MAIN_FRAME_ID, self.track.GetMainFrameID())
 
   def testGetMatchingEvents(self):
     _MAIN_FRAME_ID = 0xffff
diff --git a/tools/android/loading/user_satisfied_lens.py b/tools/android/loading/user_satisfied_lens.py
index dd99d79..523a240e 100644
--- a/tools/android/loading/user_satisfied_lens.py
+++ b/tools/android/loading/user_satisfied_lens.py
@@ -6,6 +6,9 @@
 
 Several lenses are defined, for example FirstTextPaintLens and
 FirstSignificantPaintLens.
+
+When run from the command line, takes a lens name and a trace, and prints the
+fingerprints of the critical resources to stdout.
 """
 import logging
 import operator
@@ -24,6 +27,53 @@
   _ATTRS = ['_satisfied_msec', '_event_msec', '_postload_msec',
             '_critical_request_ids']
 
+  def CriticalRequests(self):
+    """Critical requests.
+
+    Returns:
+      A sequence of request_track.Request objects representing an estimate of
+      all requests that are necessary for the user satisfaction defined by this
+      class.
+    """
+    raise NotImplementedError
+
+  def CriticalRequestIds(self):
+    """Ids of critical requests."""
+    return set(rq.request_id for rq in self.CriticalRequests())
+
+  def CriticalFingerprints(self):
+    """Fingerprints of critical requests."""
+    return set(rq.fingerprint for rq in self.CriticalRequests())
+
+  def PostloadTimeMsec(self):
+    """Return postload time.
+
+    The postload time is an estimate of the amount of time needed by chrome to
+    transform the critical results into the satisfying event.
+
+    Returns:
+      Postload time in milliseconds.
+    """
+    return 0
+
+
+class RequestFingerprintLens(_UserSatisfiedLens):
+  """A lens built using requests in a trace that match a set of fingerprints."""
+  def __init__(self, trace, fingerprints):
+    fingerprints = set(fingerprints)
+    self._critical_requests = [rq for rq in trace.request_track.GetEvents()
+                               if rq.fingerprint in fingerprints]
+
+  def CriticalRequests(self):
+    """Ids of critical requests."""
+    return set(self._critical_requests)
+
+
+class _FirstEventLens(_UserSatisfiedLens):
+  """Helper abstract subclass that defines users first event manipulations."""
+  # pylint can't handle abstract subclasses.
+  # pylint: disable=abstract-method
+
   def __init__(self, trace):
     """Initialize the lens.
 
@@ -36,34 +86,23 @@
     self._critical_request_ids = None
     if trace is None:
       return
-    self._CalculateTimes(trace.tracing_track)
-    critical_requests = self._RequestsBefore(
+    self._CalculateTimes(trace)
+    self._critical_requests = self._RequestsBefore(
         trace.request_track, self._satisfied_msec)
-    self._critical_request_ids = set(rq.request_id for rq in critical_requests)
-    if critical_requests:
-      last_load = max(rq.end_msec for rq in critical_requests)
+    self._critical_request_ids = set(rq.request_id
+                                     for rq in self._critical_requests)
+    if self._critical_requests:
+      last_load = max(rq.end_msec for rq in self._critical_requests)
     else:
       last_load = float('inf')
     self._postload_msec = self._event_msec - last_load
 
   def CriticalRequests(self):
-    """Request ids of critical requests.
-
-    Returns:
-      A set of request ids (as strings) of an estimate of all requests that are
-      necessary for the user satisfaction defined by this class.
-    """
-    return self._critical_request_ids
+    """Override."""
+    return self._critical_requests
 
   def PostloadTimeMsec(self):
-    """Return postload time.
-
-    The postload time is an estimate of the amount of time needed by chrome to
-    transform the critical results into the satisfying event.
-
-    Returns:
-      Postload time in milliseconds.
-    """
+    """Override."""
     return self._postload_msec
 
   def ToJsonDict(self):
@@ -75,7 +114,7 @@
     return common_util.DeserializeAttributesFromJsonDict(
         json_dict, result, cls._ATTRS)
 
-  def _CalculateTimes(self, tracing_track):
+  def _CalculateTimes(self, trace):
     """Subclasses should implement to set _satisfied_msec and _event_msec."""
     raise NotImplementedError
 
@@ -84,26 +123,19 @@
     return [rq for rq in request_track.GetEvents()
             if rq.end_msec <= time_ms]
 
-
-class _FirstEventLens(_UserSatisfiedLens):
-  """Helper abstract subclass that defines users first event manipulations."""
-  # pylint can't handle abstract subclasses.
-  # pylint: disable=abstract-method
-
   @classmethod
   def _CheckCategory(cls, tracing_track, category):
     assert category in tracing_track.Categories(), (
         'The "%s" category must be enabled.' % category)
 
   @classmethod
-  def _ExtractFirstTiming(cls, times):
+  def _ExtractBestTiming(cls, times):
     if not times:
       return float('inf')
-    if len(times) != 1:
-      # TODO(mattcary): in some cases a trace has two first paint events. Why?
-      logging.error('%d %s with spread of %s', len(times),
-                    str(cls), max(times) - min(times))
-    return float(min(times))
+    assert len(times) == 1, \
+        'Unexpected duplicate {}: {} with spread of {}'.format(
+            str(cls), len(times), max(times) - min(times))
+    return float(max(times))
 
 
 class FirstTextPaintLens(_FirstEventLens):
@@ -112,12 +144,13 @@
   This event is taken directly from a trace.
   """
   _EVENT_CATEGORY = 'blink.user_timing'
-  def _CalculateTimes(self, tracing_track):
-    self._CheckCategory(tracing_track, self._EVENT_CATEGORY)
-    first_paints = [e.start_msec for e in tracing_track.GetEvents()
-                    if e.Matches(self._EVENT_CATEGORY, 'firstPaint')]
+  def _CalculateTimes(self, trace):
+    self._CheckCategory(trace.tracing_track, self._EVENT_CATEGORY)
+    first_paints = [
+        e.start_msec for e in trace.tracing_track.GetMatchingMainFrameEvents(
+            'blink.user_timing', 'firstPaint')]
     self._satisfied_msec = self._event_msec = \
-        self._ExtractFirstTiming(first_paints)
+        self._ExtractBestTiming(first_paints)
 
 
 class FirstContentfulPaintLens(_FirstEventLens):
@@ -127,12 +160,13 @@
   by filtering out things like background paint from firstPaint.
   """
   _EVENT_CATEGORY = 'blink.user_timing'
-  def _CalculateTimes(self, tracing_track):
-    self._CheckCategory(tracing_track, self._EVENT_CATEGORY)
-    first_paints = [e.start_msec for e in tracing_track.GetEvents()
-                    if e.Matches(self._EVENT_CATEGORY, 'firstContentfulPaint')]
+  def _CalculateTimes(self, trace):
+    self._CheckCategory(trace.tracing_track, self._EVENT_CATEGORY)
+    first_paints = [
+        e.start_msec for e in trace.tracing_track.GetMatchingMainFrameEvents(
+            'blink.user_timing', 'firstContentfulPaint')]
     self._satisfied_msec = self._event_msec = \
-       self._ExtractFirstTiming(first_paints)
+       self._ExtractBestTiming(first_paints)
 
 
 class FirstSignificantPaintLens(_FirstEventLens):
@@ -143,12 +177,18 @@
   that is the observable event.
   """
   _FIRST_LAYOUT_COUNTER = 'LayoutObjectsThatHadNeverHadLayout'
-  _EVENT_CATEGORY = 'disabled-by-default-blink.debug.layout'
-  def _CalculateTimes(self, tracing_track):
-    self._CheckCategory(tracing_track, self._EVENT_CATEGORY)
+  _EVENT_CATEGORIES = ['blink', 'disabled-by-default-blink.debug.layout']
+  def _CalculateTimes(self, trace):
+    for cat in self._EVENT_CATEGORIES:
+      self._CheckCategory(trace.tracing_track, cat)
     sync_paint_times = []
     layouts = []  # (layout item count, msec).
-    for e in tracing_track.GetEvents():
+    for e in trace.tracing_track.GetEvents():
+      if ('frame' in e.args and
+          e.args['frame'] != trace.tracing_track.GetMainFrameID()):
+        continue
+      # If we don't know have a frame id, we assume it applies to all events.
+
       # TODO(mattcary): is this the right paint event? Check if synchronized
       # paints appear at the same time as the first*Paint events, above.
       if e.Matches('blink', 'FrameView::synchronizedPaint'):
@@ -158,7 +198,25 @@
         layouts.append((e.args['counters'][self._FIRST_LAYOUT_COUNTER],
                         e.start_msec))
     assert layouts, 'No layout events'
+    assert sync_paint_times,'No sync paint times'
     layouts.sort(key=operator.itemgetter(0), reverse=True)
     self._satisfied_msec = layouts[0][1]
-    self._event_msec = self._ExtractFirstTiming([
-        min(t for t in sync_paint_times if t > self._satisfied_msec)])
+    self._event_msec = min(t for t in sync_paint_times
+                           if t > self._satisfied_msec)
+
+
+def main(lens_name, trace_file):
+  assert (lens_name in globals() and
+          not lens_name.startswith('_') and
+          lens_name.endswith('Lens')), 'Bad lens %s' % lens_name
+  lens_cls = globals()[lens_name]
+  trace = loading_trace.LoadingTrace.FromJsonFile(trace_file)
+  lens = lens_cls(trace)
+  for fp in sorted(lens.CriticalFingerprints()):
+    print fp
+
+
+if __name__ == '__main__':
+  import sys
+  import loading_trace
+  main(sys.argv[1], sys.argv[2])
diff --git a/tools/android/loading/user_satisfied_lens_unittest.py b/tools/android/loading/user_satisfied_lens_unittest.py
index c7cdb102..c603bbe5 100644
--- a/tools/android/loading/user_satisfied_lens_unittest.py
+++ b/tools/android/loading/user_satisfied_lens_unittest.py
@@ -32,51 +32,65 @@
     return rq
 
   def testFirstContentfulPaintLens(self):
+    MAINFRAME = 1
+    SUBFRAME = 2
     loading_trace = test_utils.LoadingTraceFromEvents(
         [self._RequestAt(1), self._RequestAt(10), self._RequestAt(20)],
         trace_events=[{'ts': 0, 'ph': 'I',
                        'cat': 'blink.some_other_user_timing',
                        'name': 'firstContentfulPaint'},
-                      {'ts': 9 * self.MILLI_TO_MICRO, 'ph': 'I',
+                      {'ts': 30 * self.MILLI_TO_MICRO, 'ph': 'I',
                        'cat': 'blink.user_timing',
                        'name': 'firstDiscontentPaint'},
+                      {'ts': 5 * self.MILLI_TO_MICRO, 'ph': 'I',
+                       'cat': 'blink.user_timing',
+                       'name': 'firstContentfulPaint',
+                       'args': {'frame': SUBFRAME} },
                       {'ts': 12 * self.MILLI_TO_MICRO, 'ph': 'I',
                        'cat': 'blink.user_timing',
-                       'name': 'firstContentfulPaint'},
-                      {'ts': 22 * self.MILLI_TO_MICRO, 'ph': 'I',
-                       'cat': 'blink.user_timing',
-                       'name': 'firstContentfulPaint'}])
+                       'name': 'firstContentfulPaint',
+                       'args': {'frame': MAINFRAME}}])
+    loading_trace.tracing_track.SetMainFrameID(MAINFRAME)
     lens = user_satisfied_lens.FirstContentfulPaintLens(loading_trace)
-    self.assertEqual(set(['0.1', '0.2']), lens.CriticalRequests())
+    self.assertEqual(set(['0.1', '0.2']), lens.CriticalRequestIds())
     self.assertEqual(1, lens.PostloadTimeMsec())
 
   def testCantGetNoSatisfaction(self):
+    MAINFRAME = 1
     loading_trace = test_utils.LoadingTraceFromEvents(
         [self._RequestAt(1), self._RequestAt(10), self._RequestAt(20)],
         trace_events=[{'ts': 0, 'ph': 'I',
                        'cat': 'not_my_cat',
-                       'name': 'someEvent'}])
+                       'name': 'someEvent',
+                       'args': {'frame': MAINFRAME}}])
+    loading_trace.tracing_track.SetMainFrameID(MAINFRAME)
     lens = user_satisfied_lens.FirstContentfulPaintLens(loading_trace)
-    self.assertEqual(set(['0.1', '0.2', '0.3']), lens.CriticalRequests())
+    self.assertEqual(set(['0.1', '0.2', '0.3']), lens.CriticalRequestIds())
     self.assertEqual(float('inf'), lens.PostloadTimeMsec())
 
   def testFirstTextPaintLens(self):
+    MAINFRAME = 1
+    SUBFRAME = 2
     loading_trace = test_utils.LoadingTraceFromEvents(
         [self._RequestAt(1), self._RequestAt(10), self._RequestAt(20)],
         trace_events=[{'ts': 0, 'ph': 'I',
                        'cat': 'blink.some_other_user_timing',
                        'name': 'firstPaint'},
-                      {'ts': 9 * self.MILLI_TO_MICRO, 'ph': 'I',
+                      {'ts': 30 * self.MILLI_TO_MICRO, 'ph': 'I',
                        'cat': 'blink.user_timing',
-                       'name': 'firstishPaint'},
+                       'name': 'firstishPaint',
+                       'args': {'frame': MAINFRAME}},
+                      {'ts': 3 * self.MILLI_TO_MICRO, 'ph': 'I',
+                       'cat': 'blink.user_timing',
+                       'name': 'firstPaint',
+                       'args': {'frame': SUBFRAME}},
                       {'ts': 12 * self.MILLI_TO_MICRO, 'ph': 'I',
                        'cat': 'blink.user_timing',
-                       'name': 'firstPaint'},
-                      {'ts': 22 * self.MILLI_TO_MICRO, 'ph': 'I',
-                       'cat': 'blink.user_timing',
-                       'name': 'firstPaint'}])
+                       'name': 'firstPaint',
+                       'args': {'frame': MAINFRAME}}])
+    loading_trace.tracing_track.SetMainFrameID(MAINFRAME)
     lens = user_satisfied_lens.FirstTextPaintLens(loading_trace)
-    self.assertEqual(set(['0.1', '0.2']), lens.CriticalRequests())
+    self.assertEqual(set(['0.1', '0.2']), lens.CriticalRequestIds())
     self.assertEqual(1, lens.PostloadTimeMsec())
 
   def testFirstSignificantPaintLens(self):
@@ -112,9 +126,37 @@
                            'LayoutObjectsThatHadNeverHadLayout': 10
                        } } } ])
     lens = user_satisfied_lens.FirstSignificantPaintLens(loading_trace)
-    self.assertEqual(set(['0.1', '0.2']), lens.CriticalRequests())
+    self.assertEqual(set(['0.1', '0.2']), lens.CriticalRequestIds())
     self.assertEqual(7, lens.PostloadTimeMsec())
 
+  def testRequestFingerprintLens(self):
+    MAINFRAME = 1
+    SUBFRAME = 2
+    loading_trace = test_utils.LoadingTraceFromEvents(
+        [self._RequestAt(1), self._RequestAt(10), self._RequestAt(20)],
+        trace_events=[{'ts': 0, 'ph': 'I',
+                       'cat': 'blink.some_other_user_timing',
+                       'name': 'firstContentfulPaint'},
+                      {'ts': 30 * self.MILLI_TO_MICRO, 'ph': 'I',
+                       'cat': 'blink.user_timing',
+                       'name': 'firstDiscontentPaint'},
+                      {'ts': 5 * self.MILLI_TO_MICRO, 'ph': 'I',
+                       'cat': 'blink.user_timing',
+                       'name': 'firstContentfulPaint',
+                       'args': {'frame': SUBFRAME} },
+                      {'ts': 12 * self.MILLI_TO_MICRO, 'ph': 'I',
+                       'cat': 'blink.user_timing',
+                       'name': 'firstContentfulPaint',
+                       'args': {'frame': MAINFRAME}}])
+    loading_trace.tracing_track.SetMainFrameID(MAINFRAME)
+    lens = user_satisfied_lens.FirstContentfulPaintLens(loading_trace)
+    self.assertEqual(set(['0.1', '0.2']), lens.CriticalRequestIds())
+    self.assertEqual(1, lens.PostloadTimeMsec())
+    request_lens = user_satisfied_lens.RequestFingerprintLens(
+      loading_trace, lens.CriticalFingerprints())
+    self.assertEqual(set(['0.1', '0.2']), request_lens.CriticalRequestIds())
+    self.assertEqual(0, request_lens.PostloadTimeMsec())
+
 
 if __name__ == '__main__':
   unittest.main()
diff --git a/tools/clang/blink_gc_plugin/BlinkGCPluginConsumer.cpp b/tools/clang/blink_gc_plugin/BlinkGCPluginConsumer.cpp
index 21ef6e3..1a32def 100644
--- a/tools/clang/blink_gc_plugin/BlinkGCPluginConsumer.cpp
+++ b/tools/clang/blink_gc_plugin/BlinkGCPluginConsumer.cpp
@@ -8,6 +8,9 @@
 #include <set>
 
 #include "CheckDispatchVisitor.h"
+#include "CheckFieldsVisitor.h"
+#include "CheckFinalizerVisitor.h"
+#include "CheckGCRootsVisitor.h"
 #include "CheckTraceVisitor.h"
 #include "CollectVisitor.h"
 #include "JsonWriter.h"
@@ -19,136 +22,6 @@
 
 namespace {
 
-const char kClassMustLeftMostlyDeriveGC[] =
-    "[blink-gc] Class %0 must derive its GC base in the left-most position.";
-
-const char kClassRequiresTraceMethod[] =
-    "[blink-gc] Class %0 requires a trace method.";
-
-const char kBaseRequiresTracing[] =
-    "[blink-gc] Base class %0 of derived class %1 requires tracing.";
-
-const char kBaseRequiresTracingNote[] =
-    "[blink-gc] Untraced base class %0 declared here:";
-
-const char kFieldsRequireTracing[] =
-    "[blink-gc] Class %0 has untraced fields that require tracing.";
-
-const char kFieldRequiresTracingNote[] =
-    "[blink-gc] Untraced field %0 declared here:";
-
-const char kClassContainsInvalidFields[] =
-    "[blink-gc] Class %0 contains invalid fields.";
-
-const char kClassContainsGCRoot[] =
-    "[blink-gc] Class %0 contains GC root in field %1.";
-
-const char kClassRequiresFinalization[] =
-    "[blink-gc] Class %0 requires finalization.";
-
-const char kClassDoesNotRequireFinalization[] =
-    "[blink-gc] Class %0 may not require finalization.";
-
-const char kFinalizerAccessesFinalizedField[] =
-    "[blink-gc] Finalizer %0 accesses potentially finalized field %1.";
-
-const char kFinalizerAccessesEagerlyFinalizedField[] =
-    "[blink-gc] Finalizer %0 accesses eagerly finalized field %1.";
-
-const char kRawPtrToGCManagedClassNote[] =
-    "[blink-gc] Raw pointer field %0 to a GC managed class declared here:";
-
-const char kRefPtrToGCManagedClassNote[] =
-    "[blink-gc] RefPtr field %0 to a GC managed class declared here:";
-
-const char kReferencePtrToGCManagedClassNote[] =
-    "[blink-gc] Reference pointer field %0 to a GC managed class"
-    " declared here:";
-
-const char kOwnPtrToGCManagedClassNote[] =
-    "[blink-gc] OwnPtr field %0 to a GC managed class declared here:";
-
-const char kMemberToGCUnmanagedClassNote[] =
-    "[blink-gc] Member field %0 to non-GC managed class declared here:";
-
-const char kStackAllocatedFieldNote[] =
-    "[blink-gc] Stack-allocated field %0 declared here:";
-
-const char kMemberInUnmanagedClassNote[] =
-    "[blink-gc] Member field %0 in unmanaged class declared here:";
-
-const char kPartObjectToGCDerivedClassNote[] =
-    "[blink-gc] Part-object field %0 to a GC derived class declared here:";
-
-const char kPartObjectContainsGCRootNote[] =
-    "[blink-gc] Field %0 with embedded GC root in %1 declared here:";
-
-const char kFieldContainsGCRootNote[] =
-    "[blink-gc] Field %0 defining a GC root declared here:";
-
-const char kOverriddenNonVirtualTrace[] =
-    "[blink-gc] Class %0 overrides non-virtual trace of base class %1.";
-
-const char kOverriddenNonVirtualTraceNote[] =
-    "[blink-gc] Non-virtual trace method declared here:";
-
-const char kMissingTraceDispatchMethod[] =
-    "[blink-gc] Class %0 is missing manual trace dispatch.";
-
-const char kMissingFinalizeDispatchMethod[] =
-    "[blink-gc] Class %0 is missing manual finalize dispatch.";
-
-const char kVirtualAndManualDispatch[] =
-    "[blink-gc] Class %0 contains or inherits virtual methods"
-    " but implements manual dispatching.";
-
-const char kMissingTraceDispatch[] =
-    "[blink-gc] Missing dispatch to class %0 in manual trace dispatch.";
-
-const char kMissingFinalizeDispatch[] =
-    "[blink-gc] Missing dispatch to class %0 in manual finalize dispatch.";
-
-const char kFinalizedFieldNote[] =
-    "[blink-gc] Potentially finalized field %0 declared here:";
-
-const char kEagerlyFinalizedFieldNote[] =
-    "[blink-gc] Field %0 having eagerly finalized value, declared here:";
-
-const char kUserDeclaredDestructorNote[] =
-    "[blink-gc] User-declared destructor declared here:";
-
-const char kUserDeclaredFinalizerNote[] =
-    "[blink-gc] User-declared finalizer declared here:";
-
-const char kBaseRequiresFinalizationNote[] =
-    "[blink-gc] Base class %0 requiring finalization declared here:";
-
-const char kFieldRequiresFinalizationNote[] =
-    "[blink-gc] Field %0 requiring finalization declared here:";
-
-const char kManualDispatchMethodNote[] =
-    "[blink-gc] Manual dispatch %0 declared here:";
-
-const char kDerivesNonStackAllocated[] =
-    "[blink-gc] Stack-allocated class %0 derives class %1"
-    " which is not stack allocated.";
-
-const char kClassOverridesNew[] =
-    "[blink-gc] Garbage collected class %0"
-    " is not permitted to override its new operator.";
-
-const char kClassDeclaresPureVirtualTrace[] =
-    "[blink-gc] Garbage collected class %0"
-    " is not permitted to declare a pure-virtual trace method.";
-
-const char kLeftMostBaseMustBePolymorphic[] =
-    "[blink-gc] Left-most base class %0 of derived class %1"
-    " must be polymorphic.";
-
-const char kBaseClassMustDeclareVirtualTrace[] =
-    "[blink-gc] Left-most base class %0 of derived class %1"
-    " must define a virtual trace method.";
-
 // Use a local RAV implementation to simply collect all FunctionDecls marked for
 // late template parsing. This happens with the flag -fdelayed-template-parsing,
 // which is on by default in MSVC-compatible mode.
@@ -193,7 +66,7 @@
     clang::CompilerInstance& instance,
     const BlinkGCPluginOptions& options)
     : instance_(instance),
-      diagnostic_(instance.getDiagnostics()),
+      reporter_(instance),
       options_(options),
       json_(0) {
   // Only check structures in the blink and WebKit namespaces.
@@ -201,97 +74,11 @@
 
   // Ignore GC implementation files.
   options_.ignored_directories.push_back("/heap/");
-
-  // Register warning/error messages.
-  diag_class_must_left_mostly_derive_gc_ = diagnostic_.getCustomDiagID(
-      getErrorLevel(), kClassMustLeftMostlyDeriveGC);
-  diag_class_requires_trace_method_ =
-      diagnostic_.getCustomDiagID(getErrorLevel(), kClassRequiresTraceMethod);
-  diag_base_requires_tracing_ =
-      diagnostic_.getCustomDiagID(getErrorLevel(), kBaseRequiresTracing);
-  diag_fields_require_tracing_ =
-      diagnostic_.getCustomDiagID(getErrorLevel(), kFieldsRequireTracing);
-  diag_class_contains_invalid_fields_ = diagnostic_.getCustomDiagID(
-      getErrorLevel(), kClassContainsInvalidFields);
-  diag_class_contains_gc_root_ =
-      diagnostic_.getCustomDiagID(getErrorLevel(), kClassContainsGCRoot);
-  diag_class_requires_finalization_ = diagnostic_.getCustomDiagID(
-      getErrorLevel(), kClassRequiresFinalization);
-  diag_class_does_not_require_finalization_ = diagnostic_.getCustomDiagID(
-      DiagnosticsEngine::Warning, kClassDoesNotRequireFinalization);
-  diag_finalizer_accesses_finalized_field_ = diagnostic_.getCustomDiagID(
-      getErrorLevel(), kFinalizerAccessesFinalizedField);
-  diag_finalizer_eagerly_finalized_field_ = diagnostic_.getCustomDiagID(
-      getErrorLevel(), kFinalizerAccessesEagerlyFinalizedField);
-  diag_overridden_non_virtual_trace_ = diagnostic_.getCustomDiagID(
-      getErrorLevel(), kOverriddenNonVirtualTrace);
-  diag_missing_trace_dispatch_method_ = diagnostic_.getCustomDiagID(
-      getErrorLevel(), kMissingTraceDispatchMethod);
-  diag_missing_finalize_dispatch_method_ = diagnostic_.getCustomDiagID(
-      getErrorLevel(), kMissingFinalizeDispatchMethod);
-  diag_virtual_and_manual_dispatch_ =
-      diagnostic_.getCustomDiagID(getErrorLevel(), kVirtualAndManualDispatch);
-  diag_missing_trace_dispatch_ =
-      diagnostic_.getCustomDiagID(getErrorLevel(), kMissingTraceDispatch);
-  diag_missing_finalize_dispatch_ =
-      diagnostic_.getCustomDiagID(getErrorLevel(), kMissingFinalizeDispatch);
-  diag_derives_non_stack_allocated_ =
-      diagnostic_.getCustomDiagID(getErrorLevel(), kDerivesNonStackAllocated);
-  diag_class_overrides_new_ =
-      diagnostic_.getCustomDiagID(getErrorLevel(), kClassOverridesNew);
-  diag_class_declares_pure_virtual_trace_ = diagnostic_.getCustomDiagID(
-      getErrorLevel(), kClassDeclaresPureVirtualTrace);
-  diag_left_most_base_must_be_polymorphic_ = diagnostic_.getCustomDiagID(
-      getErrorLevel(), kLeftMostBaseMustBePolymorphic);
-  diag_base_class_must_declare_virtual_trace_ = diagnostic_.getCustomDiagID(
-      getErrorLevel(), kBaseClassMustDeclareVirtualTrace);
-
-  // Register note messages.
-  diag_base_requires_tracing_note_ = diagnostic_.getCustomDiagID(
-      DiagnosticsEngine::Note, kBaseRequiresTracingNote);
-  diag_field_requires_tracing_note_ = diagnostic_.getCustomDiagID(
-      DiagnosticsEngine::Note, kFieldRequiresTracingNote);
-  diag_raw_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID(
-      DiagnosticsEngine::Note, kRawPtrToGCManagedClassNote);
-  diag_ref_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID(
-      DiagnosticsEngine::Note, kRefPtrToGCManagedClassNote);
-  diag_reference_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID(
-      DiagnosticsEngine::Note, kReferencePtrToGCManagedClassNote);
-  diag_own_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID(
-      DiagnosticsEngine::Note, kOwnPtrToGCManagedClassNote);
-  diag_member_to_gc_unmanaged_class_note_ = diagnostic_.getCustomDiagID(
-      DiagnosticsEngine::Note, kMemberToGCUnmanagedClassNote);
-  diag_stack_allocated_field_note_ = diagnostic_.getCustomDiagID(
-      DiagnosticsEngine::Note, kStackAllocatedFieldNote);
-  diag_member_in_unmanaged_class_note_ = diagnostic_.getCustomDiagID(
-      DiagnosticsEngine::Note, kMemberInUnmanagedClassNote);
-  diag_part_object_to_gc_derived_class_note_ = diagnostic_.getCustomDiagID(
-      DiagnosticsEngine::Note, kPartObjectToGCDerivedClassNote);
-  diag_part_object_contains_gc_root_note_ = diagnostic_.getCustomDiagID(
-      DiagnosticsEngine::Note, kPartObjectContainsGCRootNote);
-  diag_field_contains_gc_root_note_ = diagnostic_.getCustomDiagID(
-      DiagnosticsEngine::Note, kFieldContainsGCRootNote);
-  diag_finalized_field_note_ = diagnostic_.getCustomDiagID(
-      DiagnosticsEngine::Note, kFinalizedFieldNote);
-  diag_eagerly_finalized_field_note_ = diagnostic_.getCustomDiagID(
-      DiagnosticsEngine::Note, kEagerlyFinalizedFieldNote);
-  diag_user_declared_destructor_note_ = diagnostic_.getCustomDiagID(
-      DiagnosticsEngine::Note, kUserDeclaredDestructorNote);
-  diag_user_declared_finalizer_note_ = diagnostic_.getCustomDiagID(
-      DiagnosticsEngine::Note, kUserDeclaredFinalizerNote);
-  diag_base_requires_finalization_note_ = diagnostic_.getCustomDiagID(
-      DiagnosticsEngine::Note, kBaseRequiresFinalizationNote);
-  diag_field_requires_finalization_note_ = diagnostic_.getCustomDiagID(
-      DiagnosticsEngine::Note, kFieldRequiresFinalizationNote);
-  diag_overridden_non_virtual_trace_note_ = diagnostic_.getCustomDiagID(
-      DiagnosticsEngine::Note, kOverriddenNonVirtualTraceNote);
-  diag_manual_dispatch_method_note_ = diagnostic_.getCustomDiagID(
-      DiagnosticsEngine::Note, kManualDispatchMethodNote);
 }
 
 void BlinkGCPluginConsumer::HandleTranslationUnit(ASTContext& context) {
   // Don't run the plugin if the compilation unit is already invalid.
-  if (diagnostic_.hasErrorOccurred())
+  if (reporter_.hasErrorOccurred())
     return;
 
   ParseFunctionTemplates(context.getTranslationUnitDecl());
@@ -393,14 +180,14 @@
   if (info->IsStackAllocated()) {
     for (auto& base : info->GetBases())
       if (!base.second.info()->IsStackAllocated())
-        ReportDerivesNonStackAllocated(info, &base.second);
+        reporter_.DerivesNonStackAllocated(info, &base.second);
   }
 
   if (CXXMethodDecl* trace = info->GetTraceMethod()) {
     if (trace->isPure())
-      ReportClassDeclaresPureVirtualTrace(info, trace);
+      reporter_.ClassDeclaresPureVirtualTrace(info, trace);
   } else if (info->RequiresTraceMethod()) {
-    ReportClassRequiresTraceMethod(info);
+    reporter_.ClassRequiresTraceMethod(info);
   }
 
   // Check polymorphic classes that are GC-derived or have a trace method.
@@ -412,9 +199,9 @@
   }
 
   {
-    CheckFieldsVisitor visitor(options_);
+    CheckFieldsVisitor visitor;
     if (visitor.ContainsInvalidFields(info))
-      ReportClassContainsInvalidFields(info, visitor.invalid_fields());
+      reporter_.ClassContainsInvalidFields(info, visitor.invalid_fields());
   }
 
   if (info->IsGCDerived()) {
@@ -423,13 +210,13 @@
       CheckDispatch(info);
       if (CXXMethodDecl* newop = info->DeclaresNewOperator())
         if (!Config::IsIgnoreAnnotated(newop))
-          ReportClassOverridesNew(info, newop);
+          reporter_.ClassOverridesNew(info, newop);
     }
 
     {
       CheckGCRootsVisitor visitor;
       if (visitor.ContainsGCRoots(info))
-        ReportClassContainsGCRoots(info, visitor.gc_roots());
+        reporter_.ClassContainsGCRoots(info, visitor.gc_roots());
     }
 
     if (info->NeedsFinalization())
@@ -513,7 +300,7 @@
         if (trace->isVirtual())
           return;
       }
-      ReportBaseClassMustDeclareVirtualTrace(info, left_most);
+      reporter_.BaseClassMustDeclareVirtualTrace(info, left_most);
       return;
     }
 
@@ -529,13 +316,13 @@
           if (CXXRecordDecl* next_left_most = GetLeftMostBase(next_base)) {
             if (DeclaresVirtualMethods(next_left_most))
               return;
-            ReportLeftMostBaseMustBePolymorphic(info, next_left_most);
+            reporter_.LeftMostBaseMustBePolymorphic(info, next_left_most);
             return;
           }
         }
       }
     }
-    ReportLeftMostBaseMustBePolymorphic(info, left_most);
+    reporter_.LeftMostBaseMustBePolymorphic(info, left_most);
   }
 }
 
@@ -567,7 +354,7 @@
   if (!left_most)
     return;
   if (!Config::IsGCBase(left_most->getName()))
-    ReportClassMustLeftMostlyDeriveGC(info);
+    reporter_.ClassMustLeftMostlyDeriveGC(info);
 }
 
 void BlinkGCPluginConsumer::CheckDispatch(RecordInfo* info) {
@@ -583,18 +370,18 @@
   // Check that dispatch methods are defined at the base.
   if (base == info->record()) {
     if (!trace_dispatch)
-      ReportMissingTraceDispatchMethod(info);
+      reporter_.MissingTraceDispatchMethod(info);
     if (finalized && !finalize_dispatch)
-      ReportMissingFinalizeDispatchMethod(info);
+      reporter_.MissingFinalizeDispatchMethod(info);
     if (!finalized && finalize_dispatch) {
-      ReportClassRequiresFinalization(info);
-      NoteUserDeclaredFinalizer(finalize_dispatch);
+      reporter_.ClassRequiresFinalization(info);
+      reporter_.NoteUserDeclaredFinalizer(finalize_dispatch);
     }
   }
 
   // Check that classes implementing manual dispatch do not have vtables.
   if (info->record()->isPolymorphic()) {
-    ReportVirtualAndManualDispatch(
+    reporter_.VirtualAndManualDispatch(
         info, trace_dispatch ? trace_dispatch : finalize_dispatch);
   }
 
@@ -610,14 +397,14 @@
     CheckDispatchVisitor visitor(info);
     visitor.TraverseStmt(defn->getBody());
     if (!visitor.dispatched_to_receiver())
-      ReportMissingTraceDispatch(defn, info);
+      reporter_.MissingTraceDispatch(defn, info);
   }
 
   if (finalized && finalize_dispatch && finalize_dispatch->isDefined(defn)) {
     CheckDispatchVisitor visitor(info);
     visitor.TraverseStmt(defn->getBody());
     if (!visitor.dispatched_to_receiver())
-      ReportMissingFinalizeDispatch(defn, info);
+      reporter_.MissingFinalizeDispatch(defn, info);
   }
 }
 
@@ -631,7 +418,7 @@
       CheckFinalizerVisitor visitor(&cache_, info->IsEagerlyFinalized());
       visitor.TraverseCXXMethodDecl(dtor);
       if (!visitor.finalized_fields().empty()) {
-        ReportFinalizerAccessesFinalizedFields(
+        reporter_.FinalizerAccessesFinalizedFields(
             dtor, visitor.finalized_fields());
       }
     }
@@ -644,23 +431,23 @@
 
   // Report the finalization error, and proceed to print possible causes for
   // the finalization requirement.
-  ReportClassRequiresFinalization(info);
+  reporter_.ClassRequiresFinalization(info);
 
   if (dtor && dtor->isUserProvided())
-    NoteUserDeclaredDestructor(dtor);
+    reporter_.NoteUserDeclaredDestructor(dtor);
 
   for (auto& base : info->GetBases())
     if (base.second.info()->NeedsFinalization())
-      NoteBaseRequiresFinalization(&base.second);
+      reporter_.NoteBaseRequiresFinalization(&base.second);
 
   for (auto& field : info->GetFields())
     if (field.second.edge()->NeedsFinalization())
-      NoteField(&field.second, diag_field_requires_finalization_note_);
+      reporter_.NoteFieldRequiresFinalization(&field.second);
 }
 
 void BlinkGCPluginConsumer::CheckUnneededFinalization(RecordInfo* info) {
   if (!HasNonEmptyFinalizer(info))
-    ReportClassDoesNotRequireFinalization(info);
+    reporter_.ClassDoesNotRequireFinalization(info);
 }
 
 bool BlinkGCPluginConsumer::HasNonEmptyFinalizer(RecordInfo* info) {
@@ -748,7 +535,7 @@
   if (trace_type == Config::TRACE_METHOD) {
     for (auto& base : parent->GetBases())
       if (CXXMethodDecl* other = base.second.info()->InheritsNonVirtualTrace())
-        ReportOverriddenNonVirtualTrace(parent, trace, other);
+        reporter_.OverriddenNonVirtualTrace(parent, trace, other);
   }
 
   CheckTraceVisitor visitor(trace, parent, &cache_);
@@ -762,12 +549,12 @@
 
   for (auto& base : parent->GetBases())
     if (!base.second.IsProperlyTraced())
-      ReportBaseRequiresTracing(parent, trace, base.first);
+      reporter_.BaseRequiresTracing(parent, trace, base.first);
 
   for (auto& field : parent->GetFields()) {
     if (!field.second.IsProperlyTraced()) {
       // Discontinue once an untraced-field error is found.
-      ReportFieldsRequireTracing(parent, trace);
+      reporter_.FieldsRequireTracing(parent, trace);
       break;
     }
   }
@@ -858,11 +645,6 @@
                       GetLocString(field.second.field()->getLocStart()));
 }
 
-DiagnosticsEngine::Level BlinkGCPluginConsumer::getErrorLevel() {
-  return diagnostic_.getWarningsAsErrors() ? DiagnosticsEngine::Error
-                                           : DiagnosticsEngine::Warning;
-}
-
 std::string BlinkGCPluginConsumer::GetLocString(SourceLocation loc) {
   const SourceManager& source_manager = instance_.getSourceManager();
   PresumedLoc ploc = source_manager.getPresumedLoc(loc);
@@ -937,283 +719,3 @@
   *filename = ploc.getFilename();
   return true;
 }
-
-DiagnosticBuilder BlinkGCPluginConsumer::ReportDiagnostic(
-    SourceLocation location,
-    unsigned diag_id) {
-  SourceManager& manager = instance_.getSourceManager();
-  FullSourceLoc full_loc(location, manager);
-  return diagnostic_.Report(full_loc, diag_id);
-}
-
-void BlinkGCPluginConsumer::ReportClassMustLeftMostlyDeriveGC(
-    RecordInfo* info) {
-  ReportDiagnostic(info->record()->getInnerLocStart(),
-                   diag_class_must_left_mostly_derive_gc_)
-      << info->record();
-}
-
-void BlinkGCPluginConsumer::ReportClassRequiresTraceMethod(RecordInfo* info) {
-  ReportDiagnostic(info->record()->getInnerLocStart(),
-                   diag_class_requires_trace_method_)
-      << info->record();
-
-  for (auto& base : info->GetBases())
-    if (base.second.NeedsTracing().IsNeeded())
-      NoteBaseRequiresTracing(&base.second);
-
-  for (auto& field : info->GetFields())
-    if (!field.second.IsProperlyTraced())
-      NoteFieldRequiresTracing(info, field.first);
-}
-
-void BlinkGCPluginConsumer::ReportBaseRequiresTracing(
-    RecordInfo* derived,
-    CXXMethodDecl* trace,
-    CXXRecordDecl* base) {
-  ReportDiagnostic(trace->getLocStart(), diag_base_requires_tracing_)
-      << base << derived->record();
-}
-
-void BlinkGCPluginConsumer::ReportFieldsRequireTracing(
-    RecordInfo* info,
-    CXXMethodDecl* trace) {
-  ReportDiagnostic(trace->getLocStart(), diag_fields_require_tracing_)
-      << info->record();
-  for (auto& field : info->GetFields())
-    if (!field.second.IsProperlyTraced())
-      NoteFieldRequiresTracing(info, field.first);
-}
-
-void BlinkGCPluginConsumer::ReportClassContainsInvalidFields(
-    RecordInfo* info,
-    const CheckFieldsVisitor::Errors& errors) {
-
-  ReportDiagnostic(info->record()->getLocStart(),
-                   diag_class_contains_invalid_fields_)
-      << info->record();
-
-  for (auto& error : errors) {
-    unsigned note;
-    if (error.second == CheckFieldsVisitor::kRawPtrToGCManaged) {
-      note = diag_raw_ptr_to_gc_managed_class_note_;
-    } else if (error.second == CheckFieldsVisitor::kRefPtrToGCManaged) {
-      note = diag_ref_ptr_to_gc_managed_class_note_;
-    } else if (error.second == CheckFieldsVisitor::kReferencePtrToGCManaged) {
-      note = diag_reference_ptr_to_gc_managed_class_note_;
-    } else if (error.second == CheckFieldsVisitor::kOwnPtrToGCManaged) {
-      note = diag_own_ptr_to_gc_managed_class_note_;
-    } else if (error.second == CheckFieldsVisitor::kMemberToGCUnmanaged) {
-      note = diag_member_to_gc_unmanaged_class_note_;
-    } else if (error.second == CheckFieldsVisitor::kMemberInUnmanaged) {
-      note = diag_member_in_unmanaged_class_note_;
-    } else if (error.second == CheckFieldsVisitor::kPtrFromHeapToStack) {
-      note = diag_stack_allocated_field_note_;
-    } else if (error.second == CheckFieldsVisitor::kGCDerivedPartObject) {
-      note = diag_part_object_to_gc_derived_class_note_;
-    } else {
-      assert(false && "Unknown field error");
-    }
-    NoteField(error.first, note);
-  }
-}
-
-void BlinkGCPluginConsumer::ReportClassContainsGCRoots(
-    RecordInfo* info,
-    const CheckGCRootsVisitor::Errors& errors) {
-  for (auto& error : errors) {
-    FieldPoint* point = nullptr;
-    for (FieldPoint* path : error) {
-      if (!point) {
-        point = path;
-        ReportDiagnostic(info->record()->getLocStart(),
-                         diag_class_contains_gc_root_)
-            << info->record() << point->field();
-        continue;
-      }
-      NotePartObjectContainsGCRoot(point);
-      point = path;
-    }
-    NoteFieldContainsGCRoot(point);
-  }
-}
-
-void BlinkGCPluginConsumer::ReportFinalizerAccessesFinalizedFields(
-    CXXMethodDecl* dtor,
-    const CheckFinalizerVisitor::Errors& errors) {
-  for (auto& error : errors) {
-    bool as_eagerly_finalized = error.as_eagerly_finalized;
-    unsigned diag_error = as_eagerly_finalized ?
-                          diag_finalizer_eagerly_finalized_field_ :
-                          diag_finalizer_accesses_finalized_field_;
-    unsigned diag_note = as_eagerly_finalized ?
-                         diag_eagerly_finalized_field_note_ :
-                         diag_finalized_field_note_;
-    ReportDiagnostic(error.member->getLocStart(), diag_error)
-        << dtor << error.field->field();
-    NoteField(error.field, diag_note);
-  }
-}
-
-void BlinkGCPluginConsumer::ReportClassRequiresFinalization(RecordInfo* info) {
-  ReportDiagnostic(info->record()->getInnerLocStart(),
-                   diag_class_requires_finalization_)
-      << info->record();
-}
-
-void BlinkGCPluginConsumer::ReportClassDoesNotRequireFinalization(
-    RecordInfo* info) {
-  ReportDiagnostic(info->record()->getInnerLocStart(),
-                   diag_class_does_not_require_finalization_)
-      << info->record();
-}
-
-void BlinkGCPluginConsumer::ReportOverriddenNonVirtualTrace(
-    RecordInfo* info,
-    CXXMethodDecl* trace,
-    CXXMethodDecl* overridden) {
-  ReportDiagnostic(trace->getLocStart(), diag_overridden_non_virtual_trace_)
-      << info->record() << overridden->getParent();
-  NoteOverriddenNonVirtualTrace(overridden);
-}
-
-void BlinkGCPluginConsumer::ReportMissingTraceDispatchMethod(RecordInfo* info) {
-  ReportMissingDispatchMethod(info, diag_missing_trace_dispatch_method_);
-}
-
-void BlinkGCPluginConsumer::ReportMissingFinalizeDispatchMethod(
-    RecordInfo* info) {
-  ReportMissingDispatchMethod(info, diag_missing_finalize_dispatch_method_);
-}
-
-void BlinkGCPluginConsumer::ReportMissingDispatchMethod(
-    RecordInfo* info,
-    unsigned error) {
-  ReportDiagnostic(info->record()->getInnerLocStart(), error)
-      << info->record();
-}
-
-void BlinkGCPluginConsumer::ReportVirtualAndManualDispatch(
-    RecordInfo* info,
-    CXXMethodDecl* dispatch) {
-  ReportDiagnostic(info->record()->getInnerLocStart(),
-                   diag_virtual_and_manual_dispatch_)
-      << info->record();
-  NoteManualDispatchMethod(dispatch);
-}
-
-void BlinkGCPluginConsumer::ReportMissingTraceDispatch(
-    const FunctionDecl* dispatch,
-    RecordInfo* receiver) {
-  ReportMissingDispatch(dispatch, receiver, diag_missing_trace_dispatch_);
-}
-
-void BlinkGCPluginConsumer::ReportMissingFinalizeDispatch(
-    const FunctionDecl* dispatch,
-    RecordInfo* receiver) {
-  ReportMissingDispatch(dispatch, receiver, diag_missing_finalize_dispatch_);
-}
-
-void BlinkGCPluginConsumer::ReportMissingDispatch(
-    const FunctionDecl* dispatch,
-    RecordInfo* receiver,
-    unsigned error) {
-  ReportDiagnostic(dispatch->getLocStart(), error) << receiver->record();
-}
-
-void BlinkGCPluginConsumer::ReportDerivesNonStackAllocated(
-    RecordInfo* info,
-    BasePoint* base) {
-  ReportDiagnostic(base->spec().getLocStart(),
-                   diag_derives_non_stack_allocated_)
-      << info->record() << base->info()->record();
-}
-
-void BlinkGCPluginConsumer::ReportClassOverridesNew(
-    RecordInfo* info,
-    CXXMethodDecl* newop) {
-  ReportDiagnostic(newop->getLocStart(), diag_class_overrides_new_)
-      << info->record();
-}
-
-void BlinkGCPluginConsumer::ReportClassDeclaresPureVirtualTrace(
-    RecordInfo* info,
-    CXXMethodDecl* trace) {
-  ReportDiagnostic(trace->getLocStart(),
-                   diag_class_declares_pure_virtual_trace_)
-      << info->record();
-}
-
-void BlinkGCPluginConsumer::ReportLeftMostBaseMustBePolymorphic(
-    RecordInfo* derived,
-    CXXRecordDecl* base) {
-  ReportDiagnostic(base->getLocStart(),
-                   diag_left_most_base_must_be_polymorphic_)
-      << base << derived->record();
-}
-
-void BlinkGCPluginConsumer::ReportBaseClassMustDeclareVirtualTrace(
-    RecordInfo* derived,
-    CXXRecordDecl* base) {
-  ReportDiagnostic(base->getLocStart(),
-                   diag_base_class_must_declare_virtual_trace_)
-      << base << derived->record();
-}
-
-void BlinkGCPluginConsumer::NoteManualDispatchMethod(CXXMethodDecl* dispatch) {
-  ReportDiagnostic(dispatch->getLocStart(),
-                   diag_manual_dispatch_method_note_)
-      << dispatch;
-}
-
-void BlinkGCPluginConsumer::NoteBaseRequiresTracing(BasePoint* base) {
-  ReportDiagnostic(base->spec().getLocStart(),
-                   diag_base_requires_tracing_note_)
-      << base->info()->record();
-}
-
-void BlinkGCPluginConsumer::NoteFieldRequiresTracing(
-    RecordInfo* holder,
-    FieldDecl* field) {
-  NoteField(field, diag_field_requires_tracing_note_);
-}
-
-void BlinkGCPluginConsumer::NotePartObjectContainsGCRoot(FieldPoint* point) {
-  FieldDecl* field = point->field();
-  ReportDiagnostic(field->getLocStart(),
-                   diag_part_object_contains_gc_root_note_)
-      << field << field->getParent();
-}
-
-void BlinkGCPluginConsumer::NoteFieldContainsGCRoot(FieldPoint* point) {
-  NoteField(point, diag_field_contains_gc_root_note_);
-}
-
-void BlinkGCPluginConsumer::NoteUserDeclaredDestructor(CXXMethodDecl* dtor) {
-  ReportDiagnostic(dtor->getLocStart(), diag_user_declared_destructor_note_);
-}
-
-void BlinkGCPluginConsumer::NoteUserDeclaredFinalizer(CXXMethodDecl* dtor) {
-  ReportDiagnostic(dtor->getLocStart(), diag_user_declared_finalizer_note_);
-}
-
-void BlinkGCPluginConsumer::NoteBaseRequiresFinalization(BasePoint* base) {
-  ReportDiagnostic(base->spec().getLocStart(),
-                   diag_base_requires_finalization_note_)
-      << base->info()->record();
-}
-
-void BlinkGCPluginConsumer::NoteField(FieldPoint* point, unsigned note) {
-  NoteField(point->field(), note);
-}
-
-void BlinkGCPluginConsumer::NoteField(FieldDecl* field, unsigned note) {
-  ReportDiagnostic(field->getLocStart(), note) << field;
-}
-
-void BlinkGCPluginConsumer::NoteOverriddenNonVirtualTrace(
-    CXXMethodDecl* overridden) {
-  ReportDiagnostic(overridden->getLocStart(),
-                   diag_overridden_non_virtual_trace_note_)
-      << overridden;
-}
diff --git a/tools/clang/blink_gc_plugin/BlinkGCPluginConsumer.h b/tools/clang/blink_gc_plugin/BlinkGCPluginConsumer.h
index e05bd82..bcfb3af 100644
--- a/tools/clang/blink_gc_plugin/BlinkGCPluginConsumer.h
+++ b/tools/clang/blink_gc_plugin/BlinkGCPluginConsumer.h
@@ -8,10 +8,8 @@
 #include <string>
 
 #include "BlinkGCPluginOptions.h"
-#include "CheckFieldsVisitor.h"
-#include "CheckFinalizerVisitor.h"
-#include "CheckGCRootsVisitor.h"
 #include "Config.h"
+#include "DiagnosticsReporter.h"
 #include "clang/AST/AST.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/Basic/Diagnostic.h"
@@ -75,7 +73,7 @@
 
   std::string GetLocString(clang::SourceLocation loc);
 
-  bool IsIgnored(RecordInfo* record);
+  bool IsIgnored(RecordInfo* info);
 
   bool IsIgnoredClass(RecordInfo* info);
 
@@ -85,112 +83,11 @@
 
   bool GetFilename(clang::SourceLocation loc, std::string* filename);
 
-  clang::DiagnosticBuilder ReportDiagnostic(
-      clang::SourceLocation location,
-      unsigned diag_id);
-
-  void ReportClassMustLeftMostlyDeriveGC(RecordInfo* info);
-  void ReportClassRequiresTraceMethod(RecordInfo* info);
-  void ReportBaseRequiresTracing(RecordInfo* derived,
-                                 clang::CXXMethodDecl* trace,
-                                 clang::CXXRecordDecl* base);
-  void ReportFieldsRequireTracing(RecordInfo* info,
-                                  clang::CXXMethodDecl* trace);
-  void ReportClassContainsInvalidFields(
-      RecordInfo* info,
-      const CheckFieldsVisitor::Errors& errors);
-  void ReportClassContainsGCRoots(RecordInfo* info,
-                                  const CheckGCRootsVisitor::Errors& errors);
-  void ReportFinalizerAccessesFinalizedFields(
-      clang::CXXMethodDecl* dtor,
-      const CheckFinalizerVisitor::Errors& errors);
-  void ReportClassRequiresFinalization(RecordInfo* info);
-  void ReportClassDoesNotRequireFinalization(RecordInfo* info);
-  void ReportClassMustDeclareGCMixinTraceMethod(RecordInfo* info);
-  void ReportOverriddenNonVirtualTrace(RecordInfo* info,
-                                       clang::CXXMethodDecl* trace,
-                                       clang::CXXMethodDecl* overridden);
-  void ReportMissingTraceDispatchMethod(RecordInfo* info);
-  void ReportMissingFinalizeDispatchMethod(RecordInfo* info);
-  void ReportMissingDispatchMethod(RecordInfo* info, unsigned error);
-  void ReportVirtualAndManualDispatch(RecordInfo* info,
-                                      clang::CXXMethodDecl* dispatch);
-  void ReportMissingTraceDispatch(const clang::FunctionDecl* dispatch,
-                                  RecordInfo* receiver);
-  void ReportMissingFinalizeDispatch(const clang::FunctionDecl* dispatch,
-                                     RecordInfo* receiver);
-  void ReportMissingDispatch(const clang::FunctionDecl* dispatch,
-                             RecordInfo* receiver,
-                             unsigned error);
-  void ReportDerivesNonStackAllocated(RecordInfo* info, BasePoint* base);
-  void ReportClassOverridesNew(RecordInfo* info, clang::CXXMethodDecl* newop);
-  void ReportClassDeclaresPureVirtualTrace(RecordInfo* info,
-                                           clang::CXXMethodDecl* trace);
-  void ReportLeftMostBaseMustBePolymorphic(RecordInfo* derived,
-                                           clang::CXXRecordDecl* base);
-  void ReportBaseClassMustDeclareVirtualTrace(RecordInfo* derived,
-                                              clang::CXXRecordDecl* base);
-  void NoteManualDispatchMethod(clang::CXXMethodDecl* dispatch);
-  void NoteBaseRequiresTracing(BasePoint* base);
-  void NoteFieldRequiresTracing(RecordInfo* holder, clang::FieldDecl* field);
-  void NotePartObjectContainsGCRoot(FieldPoint* point);
-  void NoteFieldContainsGCRoot(FieldPoint* point);
-  void NoteUserDeclaredDestructor(clang::CXXMethodDecl* dtor);
-  void NoteUserDeclaredFinalizer(clang::CXXMethodDecl* dtor);
-  void NoteBaseRequiresFinalization(BasePoint* base);
-  void NoteField(FieldPoint* point, unsigned note);
-  void NoteField(clang::FieldDecl* field, unsigned note);
-  void NoteOverriddenNonVirtualTrace(clang::CXXMethodDecl* overridden);
-
-  unsigned diag_class_must_left_mostly_derive_gc_;
-  unsigned diag_class_requires_trace_method_;
-  unsigned diag_base_requires_tracing_;
-  unsigned diag_fields_require_tracing_;
-  unsigned diag_class_contains_invalid_fields_;
-  unsigned diag_class_contains_gc_root_;
-  unsigned diag_class_requires_finalization_;
-  unsigned diag_class_does_not_require_finalization_;
-  unsigned diag_finalizer_accesses_finalized_field_;
-  unsigned diag_finalizer_eagerly_finalized_field_;
-  unsigned diag_overridden_non_virtual_trace_;
-  unsigned diag_missing_trace_dispatch_method_;
-  unsigned diag_missing_finalize_dispatch_method_;
-  unsigned diag_virtual_and_manual_dispatch_;
-  unsigned diag_missing_trace_dispatch_;
-  unsigned diag_missing_finalize_dispatch_;
-  unsigned diag_derives_non_stack_allocated_;
-  unsigned diag_class_overrides_new_;
-  unsigned diag_class_declares_pure_virtual_trace_;
-  unsigned diag_left_most_base_must_be_polymorphic_;
-  unsigned diag_base_class_must_declare_virtual_trace_;
-
-  unsigned diag_base_requires_tracing_note_;
-  unsigned diag_field_requires_tracing_note_;
-  unsigned diag_raw_ptr_to_gc_managed_class_note_;
-  unsigned diag_ref_ptr_to_gc_managed_class_note_;
-  unsigned diag_reference_ptr_to_gc_managed_class_note_;
-  unsigned diag_own_ptr_to_gc_managed_class_note_;
-  unsigned diag_member_to_gc_unmanaged_class_note_;
-  unsigned diag_stack_allocated_field_note_;
-  unsigned diag_member_in_unmanaged_class_note_;
-  unsigned diag_part_object_to_gc_derived_class_note_;
-  unsigned diag_part_object_contains_gc_root_note_;
-  unsigned diag_field_contains_gc_root_note_;
-  unsigned diag_finalized_field_note_;
-  unsigned diag_eagerly_finalized_field_note_;
-  unsigned diag_user_declared_destructor_note_;
-  unsigned diag_user_declared_finalizer_note_;
-  unsigned diag_base_requires_finalization_note_;
-  unsigned diag_field_requires_finalization_note_;
-  unsigned diag_overridden_non_virtual_trace_note_;
-  unsigned diag_manual_dispatch_method_note_;
-
   clang::CompilerInstance& instance_;
-  clang::DiagnosticsEngine& diagnostic_;
+  DiagnosticsReporter reporter_;
   BlinkGCPluginOptions options_;
   RecordCache cache_;
   JsonWriter* json_;
 };
 
-
 #endif  // TOOLS_BLINK_GC_PLUGIN_BLINK_GC_PLUGIN_CONSUMER_H_
diff --git a/tools/clang/blink_gc_plugin/CMakeLists.txt b/tools/clang/blink_gc_plugin/CMakeLists.txt
index 60ad1e52..009807b 100644
--- a/tools/clang/blink_gc_plugin/CMakeLists.txt
+++ b/tools/clang/blink_gc_plugin/CMakeLists.txt
@@ -10,6 +10,7 @@
   CheckTraceVisitor.cpp
   CollectVisitor.cpp
   Config.cpp
+  DiagnosticsReporter.cpp
   Edge.cpp
   RecordInfo.cpp)
 
diff --git a/tools/clang/blink_gc_plugin/CheckFieldsVisitor.cpp b/tools/clang/blink_gc_plugin/CheckFieldsVisitor.cpp
index f08710f8..e609a9706 100644
--- a/tools/clang/blink_gc_plugin/CheckFieldsVisitor.cpp
+++ b/tools/clang/blink_gc_plugin/CheckFieldsVisitor.cpp
@@ -9,9 +9,8 @@
 #include "BlinkGCPluginOptions.h"
 #include "RecordInfo.h"
 
-CheckFieldsVisitor::CheckFieldsVisitor(const BlinkGCPluginOptions& options)
-    : options_(options),
-      current_(0),
+CheckFieldsVisitor::CheckFieldsVisitor()
+    : current_(0),
       stack_allocated_host_(false) {
 }
 
diff --git a/tools/clang/blink_gc_plugin/CheckFieldsVisitor.h b/tools/clang/blink_gc_plugin/CheckFieldsVisitor.h
index d700be2..4fddede3 100644
--- a/tools/clang/blink_gc_plugin/CheckFieldsVisitor.h
+++ b/tools/clang/blink_gc_plugin/CheckFieldsVisitor.h
@@ -31,9 +31,9 @@
     kGCDerivedPartObject
   };
 
-  typedef std::vector<std::pair<FieldPoint*, Error> > Errors;
+  using Errors = std::vector<std::pair<FieldPoint*, Error>>;
 
-  explicit CheckFieldsVisitor(const BlinkGCPluginOptions& options);
+  CheckFieldsVisitor();
 
   Errors& invalid_fields();
 
@@ -46,7 +46,6 @@
  private:
   Error InvalidSmartPtr(Edge* ptr);
 
-  const BlinkGCPluginOptions& options_;
   FieldPoint* current_;
   bool stack_allocated_host_;
   bool managed_host_;
diff --git a/tools/clang/blink_gc_plugin/DiagnosticsReporter.cpp b/tools/clang/blink_gc_plugin/DiagnosticsReporter.cpp
new file mode 100644
index 0000000..0057d80d
--- /dev/null
+++ b/tools/clang/blink_gc_plugin/DiagnosticsReporter.cpp
@@ -0,0 +1,527 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "DiagnosticsReporter.h"
+
+using namespace clang;
+
+namespace {
+
+const char kClassMustLeftMostlyDeriveGC[] =
+    "[blink-gc] Class %0 must derive its GC base in the left-most position.";
+
+const char kClassRequiresTraceMethod[] =
+    "[blink-gc] Class %0 requires a trace method.";
+
+const char kBaseRequiresTracing[] =
+    "[blink-gc] Base class %0 of derived class %1 requires tracing.";
+
+const char kBaseRequiresTracingNote[] =
+    "[blink-gc] Untraced base class %0 declared here:";
+
+const char kFieldsRequireTracing[] =
+    "[blink-gc] Class %0 has untraced fields that require tracing.";
+
+const char kFieldRequiresTracingNote[] =
+    "[blink-gc] Untraced field %0 declared here:";
+
+const char kClassContainsInvalidFields[] =
+    "[blink-gc] Class %0 contains invalid fields.";
+
+const char kClassContainsGCRoot[] =
+    "[blink-gc] Class %0 contains GC root in field %1.";
+
+const char kClassRequiresFinalization[] =
+    "[blink-gc] Class %0 requires finalization.";
+
+const char kClassDoesNotRequireFinalization[] =
+    "[blink-gc] Class %0 may not require finalization.";
+
+const char kFinalizerAccessesFinalizedField[] =
+    "[blink-gc] Finalizer %0 accesses potentially finalized field %1.";
+
+const char kFinalizerAccessesEagerlyFinalizedField[] =
+    "[blink-gc] Finalizer %0 accesses eagerly finalized field %1.";
+
+const char kRawPtrToGCManagedClassNote[] =
+    "[blink-gc] Raw pointer field %0 to a GC managed class declared here:";
+
+const char kRefPtrToGCManagedClassNote[] =
+    "[blink-gc] RefPtr field %0 to a GC managed class declared here:";
+
+const char kReferencePtrToGCManagedClassNote[] =
+    "[blink-gc] Reference pointer field %0 to a GC managed class"
+    " declared here:";
+
+const char kOwnPtrToGCManagedClassNote[] =
+    "[blink-gc] OwnPtr field %0 to a GC managed class declared here:";
+
+const char kMemberToGCUnmanagedClassNote[] =
+    "[blink-gc] Member field %0 to non-GC managed class declared here:";
+
+const char kStackAllocatedFieldNote[] =
+    "[blink-gc] Stack-allocated field %0 declared here:";
+
+const char kMemberInUnmanagedClassNote[] =
+    "[blink-gc] Member field %0 in unmanaged class declared here:";
+
+const char kPartObjectToGCDerivedClassNote[] =
+    "[blink-gc] Part-object field %0 to a GC derived class declared here:";
+
+const char kPartObjectContainsGCRootNote[] =
+    "[blink-gc] Field %0 with embedded GC root in %1 declared here:";
+
+const char kFieldContainsGCRootNote[] =
+    "[blink-gc] Field %0 defining a GC root declared here:";
+
+const char kOverriddenNonVirtualTrace[] =
+    "[blink-gc] Class %0 overrides non-virtual trace of base class %1.";
+
+const char kOverriddenNonVirtualTraceNote[] =
+    "[blink-gc] Non-virtual trace method declared here:";
+
+const char kMissingTraceDispatchMethod[] =
+    "[blink-gc] Class %0 is missing manual trace dispatch.";
+
+const char kMissingFinalizeDispatchMethod[] =
+    "[blink-gc] Class %0 is missing manual finalize dispatch.";
+
+const char kVirtualAndManualDispatch[] =
+    "[blink-gc] Class %0 contains or inherits virtual methods"
+    " but implements manual dispatching.";
+
+const char kMissingTraceDispatch[] =
+    "[blink-gc] Missing dispatch to class %0 in manual trace dispatch.";
+
+const char kMissingFinalizeDispatch[] =
+    "[blink-gc] Missing dispatch to class %0 in manual finalize dispatch.";
+
+const char kFinalizedFieldNote[] =
+    "[blink-gc] Potentially finalized field %0 declared here:";
+
+const char kEagerlyFinalizedFieldNote[] =
+    "[blink-gc] Field %0 having eagerly finalized value, declared here:";
+
+const char kUserDeclaredDestructorNote[] =
+    "[blink-gc] User-declared destructor declared here:";
+
+const char kUserDeclaredFinalizerNote[] =
+    "[blink-gc] User-declared finalizer declared here:";
+
+const char kBaseRequiresFinalizationNote[] =
+    "[blink-gc] Base class %0 requiring finalization declared here:";
+
+const char kFieldRequiresFinalizationNote[] =
+    "[blink-gc] Field %0 requiring finalization declared here:";
+
+const char kManualDispatchMethodNote[] =
+    "[blink-gc] Manual dispatch %0 declared here:";
+
+const char kDerivesNonStackAllocated[] =
+    "[blink-gc] Stack-allocated class %0 derives class %1"
+    " which is not stack allocated.";
+
+const char kClassOverridesNew[] =
+    "[blink-gc] Garbage collected class %0"
+    " is not permitted to override its new operator.";
+
+const char kClassDeclaresPureVirtualTrace[] =
+    "[blink-gc] Garbage collected class %0"
+    " is not permitted to declare a pure-virtual trace method.";
+
+const char kLeftMostBaseMustBePolymorphic[] =
+    "[blink-gc] Left-most base class %0 of derived class %1"
+    " must be polymorphic.";
+
+const char kBaseClassMustDeclareVirtualTrace[] =
+    "[blink-gc] Left-most base class %0 of derived class %1"
+    " must define a virtual trace method.";
+
+} // namespace
+
+DiagnosticBuilder DiagnosticsReporter::ReportDiagnostic(
+    SourceLocation location,
+    unsigned diag_id) {
+  SourceManager& manager = instance_.getSourceManager();
+  FullSourceLoc full_loc(location, manager);
+  return diagnostic_.Report(full_loc, diag_id);
+}
+
+DiagnosticsReporter::DiagnosticsReporter(
+    clang::CompilerInstance& instance)
+    : instance_(instance),
+      diagnostic_(instance.getDiagnostics())
+{
+  // Register warning/error messages.
+  diag_class_must_left_mostly_derive_gc_ = diagnostic_.getCustomDiagID(
+      getErrorLevel(), kClassMustLeftMostlyDeriveGC);
+  diag_class_requires_trace_method_ =
+      diagnostic_.getCustomDiagID(getErrorLevel(), kClassRequiresTraceMethod);
+  diag_base_requires_tracing_ =
+      diagnostic_.getCustomDiagID(getErrorLevel(), kBaseRequiresTracing);
+  diag_fields_require_tracing_ =
+      diagnostic_.getCustomDiagID(getErrorLevel(), kFieldsRequireTracing);
+  diag_class_contains_invalid_fields_ = diagnostic_.getCustomDiagID(
+      getErrorLevel(), kClassContainsInvalidFields);
+  diag_class_contains_gc_root_ =
+      diagnostic_.getCustomDiagID(getErrorLevel(), kClassContainsGCRoot);
+  diag_class_requires_finalization_ = diagnostic_.getCustomDiagID(
+      getErrorLevel(), kClassRequiresFinalization);
+  diag_class_does_not_require_finalization_ = diagnostic_.getCustomDiagID(
+      DiagnosticsEngine::Warning, kClassDoesNotRequireFinalization);
+  diag_finalizer_accesses_finalized_field_ = diagnostic_.getCustomDiagID(
+      getErrorLevel(), kFinalizerAccessesFinalizedField);
+  diag_finalizer_eagerly_finalized_field_ = diagnostic_.getCustomDiagID(
+      getErrorLevel(), kFinalizerAccessesEagerlyFinalizedField);
+  diag_overridden_non_virtual_trace_ = diagnostic_.getCustomDiagID(
+      getErrorLevel(), kOverriddenNonVirtualTrace);
+  diag_missing_trace_dispatch_method_ = diagnostic_.getCustomDiagID(
+      getErrorLevel(), kMissingTraceDispatchMethod);
+  diag_missing_finalize_dispatch_method_ = diagnostic_.getCustomDiagID(
+      getErrorLevel(), kMissingFinalizeDispatchMethod);
+  diag_virtual_and_manual_dispatch_ =
+      diagnostic_.getCustomDiagID(getErrorLevel(), kVirtualAndManualDispatch);
+  diag_missing_trace_dispatch_ =
+      diagnostic_.getCustomDiagID(getErrorLevel(), kMissingTraceDispatch);
+  diag_missing_finalize_dispatch_ =
+      diagnostic_.getCustomDiagID(getErrorLevel(), kMissingFinalizeDispatch);
+  diag_derives_non_stack_allocated_ =
+      diagnostic_.getCustomDiagID(getErrorLevel(), kDerivesNonStackAllocated);
+  diag_class_overrides_new_ =
+      diagnostic_.getCustomDiagID(getErrorLevel(), kClassOverridesNew);
+  diag_class_declares_pure_virtual_trace_ = diagnostic_.getCustomDiagID(
+      getErrorLevel(), kClassDeclaresPureVirtualTrace);
+  diag_left_most_base_must_be_polymorphic_ = diagnostic_.getCustomDiagID(
+      getErrorLevel(), kLeftMostBaseMustBePolymorphic);
+  diag_base_class_must_declare_virtual_trace_ = diagnostic_.getCustomDiagID(
+      getErrorLevel(), kBaseClassMustDeclareVirtualTrace);
+
+  // Register note messages.
+  diag_base_requires_tracing_note_ = diagnostic_.getCustomDiagID(
+      DiagnosticsEngine::Note, kBaseRequiresTracingNote);
+  diag_field_requires_tracing_note_ = diagnostic_.getCustomDiagID(
+      DiagnosticsEngine::Note, kFieldRequiresTracingNote);
+  diag_raw_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID(
+      DiagnosticsEngine::Note, kRawPtrToGCManagedClassNote);
+  diag_ref_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID(
+      DiagnosticsEngine::Note, kRefPtrToGCManagedClassNote);
+  diag_reference_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID(
+      DiagnosticsEngine::Note, kReferencePtrToGCManagedClassNote);
+  diag_own_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID(
+      DiagnosticsEngine::Note, kOwnPtrToGCManagedClassNote);
+  diag_member_to_gc_unmanaged_class_note_ = diagnostic_.getCustomDiagID(
+      DiagnosticsEngine::Note, kMemberToGCUnmanagedClassNote);
+  diag_stack_allocated_field_note_ = diagnostic_.getCustomDiagID(
+      DiagnosticsEngine::Note, kStackAllocatedFieldNote);
+  diag_member_in_unmanaged_class_note_ = diagnostic_.getCustomDiagID(
+      DiagnosticsEngine::Note, kMemberInUnmanagedClassNote);
+  diag_part_object_to_gc_derived_class_note_ = diagnostic_.getCustomDiagID(
+      DiagnosticsEngine::Note, kPartObjectToGCDerivedClassNote);
+  diag_part_object_contains_gc_root_note_ = diagnostic_.getCustomDiagID(
+      DiagnosticsEngine::Note, kPartObjectContainsGCRootNote);
+  diag_field_contains_gc_root_note_ = diagnostic_.getCustomDiagID(
+      DiagnosticsEngine::Note, kFieldContainsGCRootNote);
+  diag_finalized_field_note_ = diagnostic_.getCustomDiagID(
+      DiagnosticsEngine::Note, kFinalizedFieldNote);
+  diag_eagerly_finalized_field_note_ = diagnostic_.getCustomDiagID(
+      DiagnosticsEngine::Note, kEagerlyFinalizedFieldNote);
+  diag_user_declared_destructor_note_ = diagnostic_.getCustomDiagID(
+      DiagnosticsEngine::Note, kUserDeclaredDestructorNote);
+  diag_user_declared_finalizer_note_ = diagnostic_.getCustomDiagID(
+      DiagnosticsEngine::Note, kUserDeclaredFinalizerNote);
+  diag_base_requires_finalization_note_ = diagnostic_.getCustomDiagID(
+      DiagnosticsEngine::Note, kBaseRequiresFinalizationNote);
+  diag_field_requires_finalization_note_ = diagnostic_.getCustomDiagID(
+      DiagnosticsEngine::Note, kFieldRequiresFinalizationNote);
+  diag_overridden_non_virtual_trace_note_ = diagnostic_.getCustomDiagID(
+      DiagnosticsEngine::Note, kOverriddenNonVirtualTraceNote);
+  diag_manual_dispatch_method_note_ = diagnostic_.getCustomDiagID(
+      DiagnosticsEngine::Note, kManualDispatchMethodNote);
+}
+
+bool DiagnosticsReporter::hasErrorOccurred() const
+{
+  return diagnostic_.hasErrorOccurred();
+}
+
+DiagnosticsEngine::Level DiagnosticsReporter::getErrorLevel() const {
+  return diagnostic_.getWarningsAsErrors() ? DiagnosticsEngine::Error
+                                           : DiagnosticsEngine::Warning;
+}
+
+void DiagnosticsReporter::ClassMustLeftMostlyDeriveGC(
+    RecordInfo* info) {
+  ReportDiagnostic(info->record()->getInnerLocStart(),
+                   diag_class_must_left_mostly_derive_gc_)
+      << info->record();
+}
+
+void DiagnosticsReporter::ClassRequiresTraceMethod(RecordInfo* info) {
+  ReportDiagnostic(info->record()->getInnerLocStart(),
+                   diag_class_requires_trace_method_)
+      << info->record();
+
+  for (auto& base : info->GetBases())
+    if (base.second.NeedsTracing().IsNeeded())
+      NoteBaseRequiresTracing(&base.second);
+
+  for (auto& field : info->GetFields())
+    if (!field.second.IsProperlyTraced())
+      NoteFieldRequiresTracing(info, field.first);
+}
+
+void DiagnosticsReporter::BaseRequiresTracing(
+    RecordInfo* derived,
+    CXXMethodDecl* trace,
+    CXXRecordDecl* base) {
+  ReportDiagnostic(trace->getLocStart(), diag_base_requires_tracing_)
+      << base << derived->record();
+}
+
+void DiagnosticsReporter::FieldsRequireTracing(
+    RecordInfo* info,
+    CXXMethodDecl* trace) {
+  ReportDiagnostic(trace->getLocStart(), diag_fields_require_tracing_)
+      << info->record();
+  for (auto& field : info->GetFields())
+    if (!field.second.IsProperlyTraced())
+      NoteFieldRequiresTracing(info, field.first);
+}
+
+void DiagnosticsReporter::ClassContainsInvalidFields(
+    RecordInfo* info,
+    const CheckFieldsVisitor::Errors& errors) {
+
+  ReportDiagnostic(info->record()->getLocStart(),
+                   diag_class_contains_invalid_fields_)
+      << info->record();
+
+  for (auto& error : errors) {
+    unsigned note;
+    if (error.second == CheckFieldsVisitor::kRawPtrToGCManaged) {
+      note = diag_raw_ptr_to_gc_managed_class_note_;
+    } else if (error.second == CheckFieldsVisitor::kRefPtrToGCManaged) {
+      note = diag_ref_ptr_to_gc_managed_class_note_;
+    } else if (error.second == CheckFieldsVisitor::kReferencePtrToGCManaged) {
+      note = diag_reference_ptr_to_gc_managed_class_note_;
+    } else if (error.second == CheckFieldsVisitor::kOwnPtrToGCManaged) {
+      note = diag_own_ptr_to_gc_managed_class_note_;
+    } else if (error.second == CheckFieldsVisitor::kMemberToGCUnmanaged) {
+      note = diag_member_to_gc_unmanaged_class_note_;
+    } else if (error.second == CheckFieldsVisitor::kMemberInUnmanaged) {
+      note = diag_member_in_unmanaged_class_note_;
+    } else if (error.second == CheckFieldsVisitor::kPtrFromHeapToStack) {
+      note = diag_stack_allocated_field_note_;
+    } else if (error.second == CheckFieldsVisitor::kGCDerivedPartObject) {
+      note = diag_part_object_to_gc_derived_class_note_;
+    } else {
+      assert(false && "Unknown field error");
+    }
+    NoteField(error.first, note);
+  }
+}
+
+void DiagnosticsReporter::ClassContainsGCRoots(
+    RecordInfo* info,
+    const CheckGCRootsVisitor::Errors& errors) {
+  for (auto& error : errors) {
+    FieldPoint* point = nullptr;
+    for (FieldPoint* path : error) {
+      if (!point) {
+        point = path;
+        ReportDiagnostic(info->record()->getLocStart(),
+                         diag_class_contains_gc_root_)
+            << info->record() << point->field();
+        continue;
+      }
+      NotePartObjectContainsGCRoot(point);
+      point = path;
+    }
+    NoteFieldContainsGCRoot(point);
+  }
+}
+
+void DiagnosticsReporter::FinalizerAccessesFinalizedFields(
+    CXXMethodDecl* dtor,
+    const CheckFinalizerVisitor::Errors& errors) {
+  for (auto& error : errors) {
+    bool as_eagerly_finalized = error.as_eagerly_finalized;
+    unsigned diag_error = as_eagerly_finalized ?
+                          diag_finalizer_eagerly_finalized_field_ :
+                          diag_finalizer_accesses_finalized_field_;
+    unsigned diag_note = as_eagerly_finalized ?
+                         diag_eagerly_finalized_field_note_ :
+                         diag_finalized_field_note_;
+    ReportDiagnostic(error.member->getLocStart(), diag_error)
+        << dtor << error.field->field();
+    NoteField(error.field, diag_note);
+  }
+}
+
+void DiagnosticsReporter::ClassRequiresFinalization(RecordInfo* info) {
+  ReportDiagnostic(info->record()->getInnerLocStart(),
+                   diag_class_requires_finalization_)
+      << info->record();
+}
+
+void DiagnosticsReporter::ClassDoesNotRequireFinalization(
+    RecordInfo* info) {
+  ReportDiagnostic(info->record()->getInnerLocStart(),
+                   diag_class_does_not_require_finalization_)
+      << info->record();
+}
+
+void DiagnosticsReporter::OverriddenNonVirtualTrace(
+    RecordInfo* info,
+    CXXMethodDecl* trace,
+    CXXMethodDecl* overridden) {
+  ReportDiagnostic(trace->getLocStart(), diag_overridden_non_virtual_trace_)
+      << info->record() << overridden->getParent();
+  NoteOverriddenNonVirtualTrace(overridden);
+}
+
+void DiagnosticsReporter::MissingTraceDispatchMethod(RecordInfo* info) {
+  ReportMissingDispatchMethod(info, diag_missing_trace_dispatch_method_);
+}
+
+void DiagnosticsReporter::MissingFinalizeDispatchMethod(
+    RecordInfo* info) {
+  ReportMissingDispatchMethod(info, diag_missing_finalize_dispatch_method_);
+}
+
+void DiagnosticsReporter::ReportMissingDispatchMethod(
+    RecordInfo* info,
+    unsigned error) {
+  ReportDiagnostic(info->record()->getInnerLocStart(), error)
+      << info->record();
+}
+
+void DiagnosticsReporter::VirtualAndManualDispatch(
+    RecordInfo* info,
+    CXXMethodDecl* dispatch) {
+  ReportDiagnostic(info->record()->getInnerLocStart(),
+                   diag_virtual_and_manual_dispatch_)
+      << info->record();
+  NoteManualDispatchMethod(dispatch);
+}
+
+void DiagnosticsReporter::MissingTraceDispatch(
+    const FunctionDecl* dispatch,
+    RecordInfo* receiver) {
+  ReportMissingDispatch(dispatch, receiver, diag_missing_trace_dispatch_);
+}
+
+void DiagnosticsReporter::MissingFinalizeDispatch(
+    const FunctionDecl* dispatch,
+    RecordInfo* receiver) {
+  ReportMissingDispatch(dispatch, receiver, diag_missing_finalize_dispatch_);
+}
+
+void DiagnosticsReporter::ReportMissingDispatch(
+    const FunctionDecl* dispatch,
+    RecordInfo* receiver,
+    unsigned error) {
+  ReportDiagnostic(dispatch->getLocStart(), error) << receiver->record();
+}
+
+void DiagnosticsReporter::DerivesNonStackAllocated(
+    RecordInfo* info,
+    BasePoint* base) {
+  ReportDiagnostic(base->spec().getLocStart(),
+                   diag_derives_non_stack_allocated_)
+      << info->record() << base->info()->record();
+}
+
+void DiagnosticsReporter::ClassOverridesNew(
+    RecordInfo* info,
+    CXXMethodDecl* newop) {
+  ReportDiagnostic(newop->getLocStart(), diag_class_overrides_new_)
+      << info->record();
+}
+
+void DiagnosticsReporter::ClassDeclaresPureVirtualTrace(
+    RecordInfo* info,
+    CXXMethodDecl* trace) {
+  ReportDiagnostic(trace->getLocStart(),
+                   diag_class_declares_pure_virtual_trace_)
+      << info->record();
+}
+
+void DiagnosticsReporter::LeftMostBaseMustBePolymorphic(
+    RecordInfo* derived,
+    CXXRecordDecl* base) {
+  ReportDiagnostic(base->getLocStart(),
+                   diag_left_most_base_must_be_polymorphic_)
+      << base << derived->record();
+}
+
+void DiagnosticsReporter::BaseClassMustDeclareVirtualTrace(
+    RecordInfo* derived,
+    CXXRecordDecl* base) {
+  ReportDiagnostic(base->getLocStart(),
+                   diag_base_class_must_declare_virtual_trace_)
+      << base << derived->record();
+}
+
+void DiagnosticsReporter::NoteManualDispatchMethod(CXXMethodDecl* dispatch) {
+  ReportDiagnostic(dispatch->getLocStart(),
+                   diag_manual_dispatch_method_note_)
+      << dispatch;
+}
+
+void DiagnosticsReporter::NoteBaseRequiresTracing(BasePoint* base) {
+  ReportDiagnostic(base->spec().getLocStart(),
+                   diag_base_requires_tracing_note_)
+      << base->info()->record();
+}
+
+void DiagnosticsReporter::NoteFieldRequiresTracing(
+    RecordInfo* holder,
+    FieldDecl* field) {
+  NoteField(field, diag_field_requires_tracing_note_);
+}
+
+void DiagnosticsReporter::NotePartObjectContainsGCRoot(FieldPoint* point) {
+  FieldDecl* field = point->field();
+  ReportDiagnostic(field->getLocStart(),
+                   diag_part_object_contains_gc_root_note_)
+      << field << field->getParent();
+}
+
+void DiagnosticsReporter::NoteFieldContainsGCRoot(FieldPoint* point) {
+  NoteField(point, diag_field_contains_gc_root_note_);
+}
+
+void DiagnosticsReporter::NoteUserDeclaredDestructor(CXXMethodDecl* dtor) {
+  ReportDiagnostic(dtor->getLocStart(), diag_user_declared_destructor_note_);
+}
+
+void DiagnosticsReporter::NoteUserDeclaredFinalizer(CXXMethodDecl* dtor) {
+  ReportDiagnostic(dtor->getLocStart(), diag_user_declared_finalizer_note_);
+}
+
+void DiagnosticsReporter::NoteBaseRequiresFinalization(BasePoint* base) {
+  ReportDiagnostic(base->spec().getLocStart(),
+                   diag_base_requires_finalization_note_)
+      << base->info()->record();
+}
+
+void DiagnosticsReporter::NoteFieldRequiresFinalization(FieldPoint* point) {
+  NoteField(point, diag_field_requires_finalization_note_);
+}
+
+void DiagnosticsReporter::NoteField(FieldPoint* point, unsigned note) {
+  NoteField(point->field(), note);
+}
+
+void DiagnosticsReporter::NoteField(FieldDecl* field, unsigned note) {
+  ReportDiagnostic(field->getLocStart(), note) << field;
+}
+
+void DiagnosticsReporter::NoteOverriddenNonVirtualTrace(
+    CXXMethodDecl* overridden) {
+  ReportDiagnostic(overridden->getLocStart(),
+                   diag_overridden_non_virtual_trace_note_)
+      << overridden;
+}
diff --git a/tools/clang/blink_gc_plugin/DiagnosticsReporter.h b/tools/clang/blink_gc_plugin/DiagnosticsReporter.h
new file mode 100644
index 0000000..2f9076ec
--- /dev/null
+++ b/tools/clang/blink_gc_plugin/DiagnosticsReporter.h
@@ -0,0 +1,137 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TOOLS_BLINK_GC_PLUGIN_DIAGNOSTICS_REPORTER_H_
+#define TOOLS_BLINK_GC_PLUGIN_DIAGNOSTICS_REPORTER_H_
+
+#include "CheckFieldsVisitor.h"
+#include "CheckFinalizerVisitor.h"
+#include "CheckGCRootsVisitor.h"
+#include "Config.h"
+#include "clang/AST/AST.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Frontend/CompilerInstance.h"
+
+class RecordInfo;
+
+// All error/warning reporting methods under one roof.
+//
+class DiagnosticsReporter {
+ public:
+  explicit DiagnosticsReporter(clang::CompilerInstance&);
+
+  bool hasErrorOccurred() const;
+  clang::DiagnosticsEngine::Level getErrorLevel() const;
+
+  void ClassMustLeftMostlyDeriveGC(RecordInfo* info);
+  void ClassRequiresTraceMethod(RecordInfo* info);
+  void BaseRequiresTracing(RecordInfo* derived,
+                           clang::CXXMethodDecl* trace,
+                           clang::CXXRecordDecl* base);
+  void FieldsRequireTracing(RecordInfo* info,
+                            clang::CXXMethodDecl* trace);
+  void ClassContainsInvalidFields(
+      RecordInfo* info,
+      const CheckFieldsVisitor::Errors& errors);
+  void ClassContainsGCRoots(RecordInfo* info,
+                            const CheckGCRootsVisitor::Errors& errors);
+  void FinalizerAccessesFinalizedFields(
+      clang::CXXMethodDecl* dtor,
+      const CheckFinalizerVisitor::Errors& errors);
+  void ClassRequiresFinalization(RecordInfo* info);
+  void ClassDoesNotRequireFinalization(RecordInfo* info);
+  void ClassMustDeclareGCMixinTraceMethod(RecordInfo* info);
+  void OverriddenNonVirtualTrace(RecordInfo* info,
+                                 clang::CXXMethodDecl* trace,
+                                 clang::CXXMethodDecl* overridden);
+  void MissingTraceDispatchMethod(RecordInfo* info);
+  void MissingFinalizeDispatchMethod(RecordInfo* info);
+  void VirtualAndManualDispatch(RecordInfo* info,
+                                clang::CXXMethodDecl* dispatch);
+  void MissingTraceDispatch(const clang::FunctionDecl* dispatch,
+                            RecordInfo* receiver);
+  void MissingFinalizeDispatch(const clang::FunctionDecl* dispatch,
+                               RecordInfo* receiver);
+  void DerivesNonStackAllocated(RecordInfo* info, BasePoint* base);
+  void ClassOverridesNew(RecordInfo* info, clang::CXXMethodDecl* newop);
+  void ClassDeclaresPureVirtualTrace(RecordInfo* info,
+                                     clang::CXXMethodDecl* trace);
+  void LeftMostBaseMustBePolymorphic(RecordInfo* derived,
+                                     clang::CXXRecordDecl* base);
+  void BaseClassMustDeclareVirtualTrace(RecordInfo* derived,
+                                              clang::CXXRecordDecl* base);
+
+  void NoteManualDispatchMethod(clang::CXXMethodDecl* dispatch);
+  void NoteBaseRequiresTracing(BasePoint* base);
+  void NoteFieldRequiresTracing(RecordInfo* holder, clang::FieldDecl* field);
+  void NotePartObjectContainsGCRoot(FieldPoint* point);
+  void NoteFieldContainsGCRoot(FieldPoint* point);
+  void NoteUserDeclaredDestructor(clang::CXXMethodDecl* dtor);
+  void NoteUserDeclaredFinalizer(clang::CXXMethodDecl* dtor);
+  void NoteBaseRequiresFinalization(BasePoint* base);
+  void NoteFieldRequiresFinalization(FieldPoint* field);
+  void NoteField(FieldPoint* point, unsigned note);
+  void NoteField(clang::FieldDecl* field, unsigned note);
+  void NoteOverriddenNonVirtualTrace(clang::CXXMethodDecl* overridden);
+
+ private:
+  clang::DiagnosticBuilder ReportDiagnostic(
+      clang::SourceLocation location,
+      unsigned diag_id);
+
+  void ReportMissingDispatchMethod(RecordInfo* info, unsigned error);
+  void ReportMissingDispatch(const clang::FunctionDecl* dispatch,
+                             RecordInfo* receiver,
+                             unsigned error);
+
+  clang::CompilerInstance& instance_;
+  clang::DiagnosticsEngine& diagnostic_;
+
+  unsigned diag_class_must_left_mostly_derive_gc_;
+  unsigned diag_class_requires_trace_method_;
+  unsigned diag_base_requires_tracing_;
+  unsigned diag_fields_require_tracing_;
+  unsigned diag_class_contains_invalid_fields_;
+  unsigned diag_class_contains_gc_root_;
+  unsigned diag_class_requires_finalization_;
+  unsigned diag_class_does_not_require_finalization_;
+  unsigned diag_finalizer_accesses_finalized_field_;
+  unsigned diag_finalizer_eagerly_finalized_field_;
+  unsigned diag_overridden_non_virtual_trace_;
+  unsigned diag_missing_trace_dispatch_method_;
+  unsigned diag_missing_finalize_dispatch_method_;
+  unsigned diag_virtual_and_manual_dispatch_;
+  unsigned diag_missing_trace_dispatch_;
+  unsigned diag_missing_finalize_dispatch_;
+  unsigned diag_derives_non_stack_allocated_;
+  unsigned diag_class_overrides_new_;
+  unsigned diag_class_declares_pure_virtual_trace_;
+  unsigned diag_left_most_base_must_be_polymorphic_;
+  unsigned diag_base_class_must_declare_virtual_trace_;
+
+  unsigned diag_base_requires_tracing_note_;
+  unsigned diag_field_requires_tracing_note_;
+  unsigned diag_raw_ptr_to_gc_managed_class_note_;
+  unsigned diag_ref_ptr_to_gc_managed_class_note_;
+  unsigned diag_reference_ptr_to_gc_managed_class_note_;
+  unsigned diag_own_ptr_to_gc_managed_class_note_;
+  unsigned diag_member_to_gc_unmanaged_class_note_;
+  unsigned diag_stack_allocated_field_note_;
+  unsigned diag_member_in_unmanaged_class_note_;
+  unsigned diag_part_object_to_gc_derived_class_note_;
+  unsigned diag_part_object_contains_gc_root_note_;
+  unsigned diag_field_contains_gc_root_note_;
+  unsigned diag_finalized_field_note_;
+  unsigned diag_eagerly_finalized_field_note_;
+  unsigned diag_user_declared_destructor_note_;
+  unsigned diag_user_declared_finalizer_note_;
+  unsigned diag_base_requires_finalization_note_;
+  unsigned diag_field_requires_finalization_note_;
+  unsigned diag_overridden_non_virtual_trace_note_;
+  unsigned diag_manual_dispatch_method_note_;
+
+};
+
+#endif // TOOLS_BLINK_GC_PLUGIN_DIAGNOSTICS_REPORTER_H_
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 07be7876..7155726 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -92427,6 +92427,8 @@
   <suffix name="websame"
       label="Link triggered prerender, rel=prerender, same domain."/>
   <suffix name="webnext" label="Link triggered prerender, rel=next."/>
+  <suffix name="offline"
+      label="Prerender triggered for saving a page for offline use."/>
   <affected-histogram name="Prerender.AbandonTimeUntilUsed"/>
   <affected-histogram name="Prerender.CookieSendType"/>
   <affected-histogram name="Prerender.CookieStatus"/>
diff --git a/ui/gfx/ipc/gfx_param_traits_macros.h b/ui/gfx/ipc/gfx_param_traits_macros.h
index cf8dec7b..f717960e 100644
--- a/ui/gfx/ipc/gfx_param_traits_macros.h
+++ b/ui/gfx/ipc/gfx_param_traits_macros.h
@@ -9,6 +9,7 @@
 #define UI_GFX_IPC_GFX_PARAM_TRAITS_MACROS_H_
 
 #include "ui/gfx/buffer_types.h"
+#include "ui/gfx/gpu_memory_buffer.h"
 #include "ui/gfx/ipc/gfx_ipc_export.h"
 #include "ipc/ipc_message_macros.h"
 
@@ -23,6 +24,26 @@
 
 IPC_ENUM_TRAITS_MAX_VALUE(gfx::BufferUsage, gfx::BufferUsage::LAST)
 
+IPC_ENUM_TRAITS_MAX_VALUE(gfx::GpuMemoryBufferType,
+                          gfx::GPU_MEMORY_BUFFER_TYPE_LAST)
+
+IPC_STRUCT_TRAITS_BEGIN(gfx::GpuMemoryBufferHandle)
+  IPC_STRUCT_TRAITS_MEMBER(id)
+  IPC_STRUCT_TRAITS_MEMBER(type)
+  IPC_STRUCT_TRAITS_MEMBER(handle)
+  IPC_STRUCT_TRAITS_MEMBER(offset)
+  IPC_STRUCT_TRAITS_MEMBER(stride)
+#if defined(USE_OZONE)
+  IPC_STRUCT_TRAITS_MEMBER(native_pixmap_handle)
+#elif defined(OS_MACOSX)
+  IPC_STRUCT_TRAITS_MEMBER(mach_port)
+#endif
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(gfx::GpuMemoryBufferId)
+  IPC_STRUCT_TRAITS_MEMBER(id)
+IPC_STRUCT_TRAITS_END()
+
 #if defined(USE_OZONE)
 IPC_STRUCT_TRAITS_BEGIN(gfx::NativePixmapHandle)
   IPC_STRUCT_TRAITS_MEMBER(fd)
diff --git a/ui/gl/generate_bindings.py b/ui/gl/generate_bindings.py
index be41ea46..1b28d2a 100755
--- a/ui/gl/generate_bindings.py
+++ b/ui/gl/generate_bindings.py
@@ -116,6 +116,10 @@
   'versions': [{ 'name': 'glBindTransformFeedback' }],
   'arguments': 'GLenum target, GLuint id', },
 { 'return_type': 'void',
+  'versions': [{ 'name': 'glBindUniformLocationCHROMIUM',
+                 'extensions': ['GL_CHROMIUM_bind_uniform_location'] }],
+  'arguments': 'GLuint program, GLint location, const char* name' },
+{ 'return_type': 'void',
   'known_as': 'glBindVertexArrayOES',
   'versions': [{ 'name': 'glBindVertexArray',
                  'extensions': ['GL_ARB_vertex_array_object'], },
diff --git a/ui/gl/gl_bindings_api_autogen_gl.h b/ui/gl/gl_bindings_api_autogen_gl.h
index a513ed20..ed809dd 100644
--- a/ui/gl/gl_bindings_api_autogen_gl.h
+++ b/ui/gl/gl_bindings_api_autogen_gl.h
@@ -42,6 +42,9 @@
 void glBindSamplerFn(GLuint unit, GLuint sampler) override;
 void glBindTextureFn(GLenum target, GLuint texture) override;
 void glBindTransformFeedbackFn(GLenum target, GLuint id) override;
+void glBindUniformLocationCHROMIUMFn(GLuint program,
+                                     GLint location,
+                                     const char* name) override;
 void glBindVertexArrayOESFn(GLuint array) override;
 void glBlendBarrierKHRFn(void) override;
 void glBlendColorFn(GLclampf red,
diff --git a/ui/gl/gl_bindings_autogen_gl.cc b/ui/gl/gl_bindings_autogen_gl.cc
index e0a78b0..42b0e27 100644
--- a/ui/gl/gl_bindings_autogen_gl.cc
+++ b/ui/gl/gl_bindings_autogen_gl.cc
@@ -46,6 +46,7 @@
   fn.glBindTextureFn =
       reinterpret_cast<glBindTextureProc>(GetGLProcAddress("glBindTexture"));
   fn.glBindTransformFeedbackFn = 0;
+  fn.glBindUniformLocationCHROMIUMFn = 0;
   fn.glBindVertexArrayOESFn = 0;
   fn.glBlendBarrierKHRFn = 0;
   fn.glBlendColorFn =
@@ -513,6 +514,9 @@
       extensions.find("GL_ARB_timer_query ") != std::string::npos;
   ext.b_GL_ARB_vertex_array_object =
       extensions.find("GL_ARB_vertex_array_object ") != std::string::npos;
+  ext.b_GL_CHROMIUM_bind_uniform_location =
+      extensions.find("GL_CHROMIUM_bind_uniform_location ") !=
+      std::string::npos;
   ext.b_GL_CHROMIUM_gles_depth_binding_hack =
       extensions.find("GL_CHROMIUM_gles_depth_binding_hack ") !=
       std::string::npos;
@@ -680,6 +684,13 @@
             GetGLProcAddress("glBindTransformFeedback"));
   }
 
+  debug_fn.glBindUniformLocationCHROMIUMFn = 0;
+  if (ext.b_GL_CHROMIUM_bind_uniform_location) {
+    fn.glBindUniformLocationCHROMIUMFn =
+        reinterpret_cast<glBindUniformLocationCHROMIUMProc>(
+            GetGLProcAddress("glBindUniformLocationCHROMIUM"));
+  }
+
   debug_fn.glBindVertexArrayOESFn = 0;
   if (ver->IsAtLeastGL(3u, 0u) || ver->IsAtLeastGLES(3u, 0u) ||
       ext.b_GL_ARB_vertex_array_object) {
@@ -2200,6 +2211,16 @@
   g_driver_gl.debug_fn.glBindTransformFeedbackFn(target, id);
 }
 
+static void GL_BINDING_CALL
+Debug_glBindUniformLocationCHROMIUM(GLuint program,
+                                    GLint location,
+                                    const char* name) {
+  GL_SERVICE_LOG("glBindUniformLocationCHROMIUM"
+                 << "(" << program << ", " << location << ", " << name << ")");
+  DCHECK(g_driver_gl.debug_fn.glBindUniformLocationCHROMIUMFn != nullptr);
+  g_driver_gl.debug_fn.glBindUniformLocationCHROMIUMFn(program, location, name);
+}
+
 static void GL_BINDING_CALL Debug_glBindVertexArrayOES(GLuint array) {
   GL_SERVICE_LOG("glBindVertexArrayOES"
                  << "(" << array << ")");
@@ -5580,6 +5601,11 @@
     debug_fn.glBindTransformFeedbackFn = fn.glBindTransformFeedbackFn;
     fn.glBindTransformFeedbackFn = Debug_glBindTransformFeedback;
   }
+  if (!debug_fn.glBindUniformLocationCHROMIUMFn) {
+    debug_fn.glBindUniformLocationCHROMIUMFn =
+        fn.glBindUniformLocationCHROMIUMFn;
+    fn.glBindUniformLocationCHROMIUMFn = Debug_glBindUniformLocationCHROMIUM;
+  }
   if (!debug_fn.glBindVertexArrayOESFn) {
     debug_fn.glBindVertexArrayOESFn = fn.glBindVertexArrayOESFn;
     fn.glBindVertexArrayOESFn = Debug_glBindVertexArrayOES;
@@ -6899,6 +6925,12 @@
   driver_->fn.glBindTransformFeedbackFn(target, id);
 }
 
+void GLApiBase::glBindUniformLocationCHROMIUMFn(GLuint program,
+                                                GLint location,
+                                                const char* name) {
+  driver_->fn.glBindUniformLocationCHROMIUMFn(program, location, name);
+}
+
 void GLApiBase::glBindVertexArrayOESFn(GLuint array) {
   driver_->fn.glBindVertexArrayOESFn(array);
 }
@@ -8807,6 +8839,14 @@
   gl_api_->glBindTransformFeedbackFn(target, id);
 }
 
+void TraceGLApi::glBindUniformLocationCHROMIUMFn(GLuint program,
+                                                 GLint location,
+                                                 const char* name) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu",
+                                "TraceGLAPI::glBindUniformLocationCHROMIUM")
+  gl_api_->glBindUniformLocationCHROMIUMFn(program, location, name);
+}
+
 void TraceGLApi::glBindVertexArrayOESFn(GLuint array) {
   TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glBindVertexArrayOES")
   gl_api_->glBindVertexArrayOESFn(array);
@@ -11060,6 +11100,15 @@
       << "Trying to call glBindTransformFeedback() without current GL context";
 }
 
+void NoContextGLApi::glBindUniformLocationCHROMIUMFn(GLuint program,
+                                                     GLint location,
+                                                     const char* name) {
+  NOTREACHED() << "Trying to call glBindUniformLocationCHROMIUM() without "
+                  "current GL context";
+  LOG(ERROR) << "Trying to call glBindUniformLocationCHROMIUM() without "
+                "current GL context";
+}
+
 void NoContextGLApi::glBindVertexArrayOESFn(GLuint array) {
   NOTREACHED()
       << "Trying to call glBindVertexArrayOES() without current GL context";
diff --git a/ui/gl/gl_bindings_autogen_gl.h b/ui/gl/gl_bindings_autogen_gl.h
index 28393dca..7019e7d 100644
--- a/ui/gl/gl_bindings_autogen_gl.h
+++ b/ui/gl/gl_bindings_autogen_gl.h
@@ -57,6 +57,10 @@
 typedef void(GL_BINDING_CALL* glBindTextureProc)(GLenum target, GLuint texture);
 typedef void(GL_BINDING_CALL* glBindTransformFeedbackProc)(GLenum target,
                                                            GLuint id);
+typedef void(GL_BINDING_CALL* glBindUniformLocationCHROMIUMProc)(
+    GLuint program,
+    GLint location,
+    const char* name);
 typedef void(GL_BINDING_CALL* glBindVertexArrayOESProc)(GLuint array);
 typedef void(GL_BINDING_CALL* glBlendBarrierKHRProc)(void);
 typedef void(GL_BINDING_CALL* glBlendColorProc)(GLclampf red,
@@ -1057,6 +1061,7 @@
   bool b_GL_ARB_texture_storage;
   bool b_GL_ARB_timer_query;
   bool b_GL_ARB_vertex_array_object;
+  bool b_GL_CHROMIUM_bind_uniform_location;
   bool b_GL_CHROMIUM_gles_depth_binding_hack;
   bool b_GL_CHROMIUM_glgetstringi_hack;
   bool b_GL_EXT_blend_func_extended;
@@ -1110,6 +1115,7 @@
   glBindSamplerProc glBindSamplerFn;
   glBindTextureProc glBindTextureFn;
   glBindTransformFeedbackProc glBindTransformFeedbackFn;
+  glBindUniformLocationCHROMIUMProc glBindUniformLocationCHROMIUMFn;
   glBindVertexArrayOESProc glBindVertexArrayOESFn;
   glBlendBarrierKHRProc glBlendBarrierKHRFn;
   glBlendColorProc glBlendColorFn;
@@ -1459,6 +1465,9 @@
   virtual void glBindSamplerFn(GLuint unit, GLuint sampler) = 0;
   virtual void glBindTextureFn(GLenum target, GLuint texture) = 0;
   virtual void glBindTransformFeedbackFn(GLenum target, GLuint id) = 0;
+  virtual void glBindUniformLocationCHROMIUMFn(GLuint program,
+                                               GLint location,
+                                               const char* name) = 0;
   virtual void glBindVertexArrayOESFn(GLuint array) = 0;
   virtual void glBlendBarrierKHRFn(void) = 0;
   virtual void glBlendColorFn(GLclampf red,
@@ -2352,6 +2361,8 @@
 #define glBindTexture ::gfx::g_current_gl_context->glBindTextureFn
 #define glBindTransformFeedback \
   ::gfx::g_current_gl_context->glBindTransformFeedbackFn
+#define glBindUniformLocationCHROMIUM \
+  ::gfx::g_current_gl_context->glBindUniformLocationCHROMIUMFn
 #define glBindVertexArrayOES ::gfx::g_current_gl_context->glBindVertexArrayOESFn
 #define glBlendBarrierKHR ::gfx::g_current_gl_context->glBlendBarrierKHRFn
 #define glBlendColor ::gfx::g_current_gl_context->glBlendColorFn
diff --git a/ui/gl/gl_bindings_autogen_mock.cc b/ui/gl/gl_bindings_autogen_mock.cc
index d813760..6098236 100644
--- a/ui/gl/gl_bindings_autogen_mock.cc
+++ b/ui/gl/gl_bindings_autogen_mock.cc
@@ -194,6 +194,14 @@
   interface_->BindTransformFeedback(target, id);
 }
 
+void GL_BINDING_CALL
+MockGLInterface::Mock_glBindUniformLocationCHROMIUM(GLuint program,
+                                                    GLint location,
+                                                    const char* name) {
+  MakeFunctionUnique("glBindUniformLocationCHROMIUM");
+  interface_->BindUniformLocationCHROMIUM(program, location, name);
+}
+
 void GL_BINDING_CALL MockGLInterface::Mock_glBindVertexArray(GLuint array) {
   MakeFunctionUnique("glBindVertexArray");
   interface_->BindVertexArrayOES(array);
@@ -2959,6 +2967,8 @@
     return reinterpret_cast<void*>(Mock_glBindTexture);
   if (strcmp(name, "glBindTransformFeedback") == 0)
     return reinterpret_cast<void*>(Mock_glBindTransformFeedback);
+  if (strcmp(name, "glBindUniformLocationCHROMIUM") == 0)
+    return reinterpret_cast<void*>(Mock_glBindUniformLocationCHROMIUM);
   if (strcmp(name, "glBindVertexArray") == 0)
     return reinterpret_cast<void*>(Mock_glBindVertexArray);
   if (strcmp(name, "glBindVertexArrayAPPLE") == 0)
diff --git a/ui/gl/gl_bindings_autogen_mock.h b/ui/gl/gl_bindings_autogen_mock.h
index 88a06fef..2a05128f 100644
--- a/ui/gl/gl_bindings_autogen_mock.h
+++ b/ui/gl/gl_bindings_autogen_mock.h
@@ -69,6 +69,10 @@
 static void GL_BINDING_CALL Mock_glBindTexture(GLenum target, GLuint texture);
 static void GL_BINDING_CALL Mock_glBindTransformFeedback(GLenum target,
                                                          GLuint id);
+static void GL_BINDING_CALL
+Mock_glBindUniformLocationCHROMIUM(GLuint program,
+                                   GLint location,
+                                   const char* name);
 static void GL_BINDING_CALL Mock_glBindVertexArray(GLuint array);
 static void GL_BINDING_CALL Mock_glBindVertexArrayAPPLE(GLuint array);
 static void GL_BINDING_CALL Mock_glBindVertexArrayOES(GLuint array);
diff --git a/ui/gl/gl_mock_autogen_gl.h b/ui/gl/gl_mock_autogen_gl.h
index 2a5a445..5490842 100644
--- a/ui/gl/gl_mock_autogen_gl.h
+++ b/ui/gl/gl_mock_autogen_gl.h
@@ -41,6 +41,8 @@
 MOCK_METHOD2(BindSampler, void(GLuint unit, GLuint sampler));
 MOCK_METHOD2(BindTexture, void(GLenum target, GLuint texture));
 MOCK_METHOD2(BindTransformFeedback, void(GLenum target, GLuint id));
+MOCK_METHOD3(BindUniformLocationCHROMIUM,
+             void(GLuint program, GLint location, const char* name));
 MOCK_METHOD1(BindVertexArrayOES, void(GLuint array));
 MOCK_METHOD0(BlendBarrierKHR, void());
 MOCK_METHOD4(BlendColor,
diff --git a/ui/views/animation/flood_fill_ink_drop_animation.cc b/ui/views/animation/flood_fill_ink_drop_animation.cc
index 4520fb4..6e177aaf 100644
--- a/ui/views/animation/flood_fill_ink_drop_animation.cc
+++ b/ui/views/animation/flood_fill_ink_drop_animation.cc
@@ -107,26 +107,22 @@
 namespace views {
 
 FloodFillInkDropAnimation::FloodFillInkDropAnimation(
-    const gfx::Size& size,
+    const gfx::Rect& clip_bounds,
     const gfx::Point& center_point,
     SkColor color)
-    : size_(size),
+    : clip_bounds_(clip_bounds),
       center_point_(center_point),
       root_layer_(ui::LAYER_NOT_DRAWN),
-      circle_layer_delegate_(color,
-                             std::max(size_.width(), size_.height()) / 2.f),
+      circle_layer_delegate_(
+          color,
+          std::max(clip_bounds_.width(), clip_bounds_.height()) / 2.f),
       ink_drop_state_(InkDropState::HIDDEN) {
   root_layer_.set_name("FloodFillInkDropAnimation:ROOT_LAYER");
   root_layer_.SetMasksToBounds(true);
-  root_layer_.SetBounds(gfx::Rect(size_));
+  root_layer_.SetBounds(clip_bounds);
 
-  const gfx::Vector2dF translate_vector =
-      center_point_ - root_layer_.bounds().CenterPoint();
-  gfx::Transform transfrom;
-  transfrom.Translate(translate_vector.x(), translate_vector.y());
-  root_layer_.SetTransform(transfrom);
-
-  const int painted_size_length = 2 * std::max(size_.width(), size_.height());
+  const int painted_size_length =
+      2 * std::max(clip_bounds_.width(), clip_bounds_.height());
 
   painted_layer_.SetBounds(gfx::Rect(painted_size_length, painted_size_length));
   painted_layer_.SetFillsBoundsOpaquely(false);
@@ -313,10 +309,10 @@
       ToRoundedPoint(circle_layer_delegate_.GetCenterPoint());
 
   gfx::Transform transform = gfx::Transform();
-  transform.Translate(root_layer_.bounds().CenterPoint().x(),
-                      root_layer_.bounds().CenterPoint().y());
+  transform.Translate(center_point_.x(), center_point_.y());
   transform.Scale(target_scale, target_scale);
-  transform.Translate(-drawn_center_point.x(), -drawn_center_point.y());
+  transform.Translate(-drawn_center_point.x() - root_layer_.bounds().x(),
+                      -drawn_center_point.y() - root_layer_.bounds().y());
 
   return transform;
 }
@@ -325,7 +321,7 @@
   // TODO(estade): get rid of this 2, but make the fade out start before the
   // active/action transform is done.
   return CalculateTransform(
-      gfx::Vector2dF(size_.width(), size_.height()).Length() / 2);
+      gfx::Vector2dF(clip_bounds_.width(), clip_bounds_.height()).Length() / 2);
 }
 
 }  // namespace views
diff --git a/ui/views/animation/flood_fill_ink_drop_animation.h b/ui/views/animation/flood_fill_ink_drop_animation.h
index 97a4cd08..303f295 100644
--- a/ui/views/animation/flood_fill_ink_drop_animation.h
+++ b/ui/views/animation/flood_fill_ink_drop_animation.h
@@ -48,7 +48,7 @@
 //
 class VIEWS_EXPORT FloodFillInkDropAnimation : public InkDropAnimation {
  public:
-  FloodFillInkDropAnimation(const gfx::Size& size,
+  FloodFillInkDropAnimation(const gfx::Rect& clip_bounds,
                             const gfx::Point& center_point,
                             SkColor color);
   ~FloodFillInkDropAnimation() override;
@@ -101,8 +101,8 @@
   // Returns the target Transform for when the ink drop is fully shown.
   gfx::Transform GetMaxSizeTargetTransform() const;
 
-  // The clip Size.
-  const gfx::Size size_;
+  // The clip bounds.
+  const gfx::Rect clip_bounds_;
 
   // The point where the Center of the ink drop's circle should be drawn.
   gfx::Point center_point_;
diff --git a/ui/views/animation/ink_drop_animation.cc b/ui/views/animation/ink_drop_animation.cc
index 717b905..214716da 100644
--- a/ui/views/animation/ink_drop_animation.cc
+++ b/ui/views/animation/ink_drop_animation.cc
@@ -91,6 +91,10 @@
   target_ink_drop_state_ = InkDropState::HIDDEN;
 }
 
+test::InkDropAnimationTestApi* InkDropAnimation::GetTestApi() {
+  return nullptr;
+}
+
 void InkDropAnimation::AnimationStartedCallback(
     InkDropState ink_drop_state,
     const ui::CallbackLayerAnimationObserver& observer) {
diff --git a/ui/views/animation/ink_drop_animation.h b/ui/views/animation/ink_drop_animation.h
index 3d4c62fc..b00be7d 100644
--- a/ui/views/animation/ink_drop_animation.h
+++ b/ui/views/animation/ink_drop_animation.h
@@ -19,6 +19,10 @@
 
 namespace views {
 
+namespace test {
+class InkDropAnimationTestApi;
+}  // namespace test
+
 // Simple base class for animations that provide visual feedback for View state.
 // Manages the attached InkDropAnimationObservers.
 //
@@ -81,6 +85,11 @@
   // animates to the target HIDDEN state.
   virtual bool IsVisible() const = 0;
 
+  // Returns a test api to access internals of this. Default implmentations
+  // should return nullptr and test specific subclasses can override to return
+  // an instance.
+  virtual test::InkDropAnimationTestApi* GetTestApi();
+
  protected:
   // Animates the ripple from the |old_ink_drop_state| to the
   // |new_ink_drop_state|. |observer| is added to all LayerAnimationSequence's
diff --git a/ui/views/animation/ink_drop_animation_controller_impl.h b/ui/views/animation/ink_drop_animation_controller_impl.h
index 41bd3f2..e075975 100644
--- a/ui/views/animation/ink_drop_animation_controller_impl.h
+++ b/ui/views/animation/ink_drop_animation_controller_impl.h
@@ -19,6 +19,10 @@
 }  // namespace base
 
 namespace views {
+namespace test {
+class InkDropAnimationControllerImplTestApi;
+}  // namespace test
+
 class InkDropAnimation;
 class InkDropHost;
 class InkDropHover;
@@ -42,8 +46,7 @@
   void SetHovered(bool is_hovered) override;
 
  private:
-  friend class InkDropAnimationControllerFactoryTest;
-  friend class InkDropAnimationControllerImplTest;
+  friend class test::InkDropAnimationControllerImplTestApi;
 
   // Destroys |ink_drop_animation_| if it's targeted to the HIDDEN state.
   void DestroyHiddenTargetedAnimations();
diff --git a/ui/views/animation/ink_drop_animation_controller_impl_unittest.cc b/ui/views/animation/ink_drop_animation_controller_impl_unittest.cc
index 923315b..8ceab47 100644
--- a/ui/views/animation/ink_drop_animation_controller_impl_unittest.cc
+++ b/ui/views/animation/ink_drop_animation_controller_impl_unittest.cc
@@ -8,7 +8,8 @@
 #include "base/test/test_simple_task_runner.h"
 #include "base/thread_task_runner_handle.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "ui/compositor/scoped_animation_duration_scale_mode.h"
+#include "ui/views/animation/ink_drop_animation.h"
+#include "ui/views/animation/test/ink_drop_animation_controller_impl_test_api.h"
 #include "ui/views/animation/test/test_ink_drop_host.h"
 
 namespace views {
@@ -23,17 +24,12 @@
  protected:
   TestInkDropHost ink_drop_host_;
 
-  bool is_hover_fading_in_or_visible() {
-    return ink_drop_animation_controller_.IsHoverFadingInOrVisible();
-  }
-
-  const InkDropHover* hover() const {
-    return ink_drop_animation_controller_.hover_.get();
-  }
-
   // The test target.
   InkDropAnimationControllerImpl ink_drop_animation_controller_;
 
+  // Allows privileged access to the the |ink_drop_hover_|.
+  test::InkDropAnimationControllerImplTestApi test_api_;
+
   // Used to control the tasks scheduled by the InkDropAnimationControllerImpl's
   // Timer.
   scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
@@ -42,19 +38,16 @@
   std::unique_ptr<base::ThreadTaskRunnerHandle> thread_task_runner_handle_;
 
  private:
-  // Ensures all animations complete immediately.
-  std::unique_ptr<ui::ScopedAnimationDurationScaleMode> zero_duration_mode_;
-
   DISALLOW_COPY_AND_ASSIGN(InkDropAnimationControllerImplTest);
 };
 
 InkDropAnimationControllerImplTest::InkDropAnimationControllerImplTest()
     : ink_drop_animation_controller_(&ink_drop_host_),
+      test_api_(&ink_drop_animation_controller_),
       task_runner_(new base::TestSimpleTaskRunner),
       thread_task_runner_handle_(
           new base::ThreadTaskRunnerHandle(task_runner_)) {
-  zero_duration_mode_.reset(new ui::ScopedAnimationDurationScaleMode(
-      ui::ScopedAnimationDurationScaleMode::ZERO_DURATION));
+  ink_drop_host_.set_disable_timers_for_test(true);
 }
 
 InkDropAnimationControllerImplTest::~InkDropAnimationControllerImplTest() {}
@@ -63,10 +56,12 @@
   ink_drop_host_.set_should_show_hover(true);
 
   ink_drop_animation_controller_.SetHovered(true);
-  EXPECT_TRUE(is_hover_fading_in_or_visible());
+  EXPECT_TRUE(test_api_.IsHoverFadingInOrVisible());
+
+  test_api_.CompleteAnimations();
 
   ink_drop_animation_controller_.SetHovered(false);
-  EXPECT_FALSE(is_hover_fading_in_or_visible());
+  EXPECT_FALSE(test_api_.IsHoverFadingInOrVisible());
 }
 
 TEST_F(InkDropAnimationControllerImplTest,
@@ -74,9 +69,10 @@
   ink_drop_host_.set_should_show_hover(true);
   ink_drop_animation_controller_.SetHovered(false);
   ink_drop_animation_controller_.AnimateToState(InkDropState::ACTION_TRIGGERED);
+  test_api_.CompleteAnimations();
 
   EXPECT_FALSE(task_runner_->HasPendingTask());
-  EXPECT_FALSE(is_hover_fading_in_or_visible());
+  EXPECT_FALSE(test_api_.IsHoverFadingInOrVisible());
 }
 
 TEST_F(InkDropAnimationControllerImplTest,
@@ -84,12 +80,13 @@
   ink_drop_host_.set_should_show_hover(true);
   ink_drop_animation_controller_.SetHovered(true);
   ink_drop_animation_controller_.AnimateToState(InkDropState::ACTION_TRIGGERED);
+  test_api_.CompleteAnimations();
 
   EXPECT_TRUE(task_runner_->HasPendingTask());
 
   task_runner_->RunPendingTasks();
 
-  EXPECT_TRUE(is_hover_fading_in_or_visible());
+  EXPECT_TRUE(test_api_.IsHoverFadingInOrVisible());
 }
 
 TEST_F(InkDropAnimationControllerImplTest,
@@ -97,12 +94,13 @@
   ink_drop_host_.set_should_show_hover(false);
   ink_drop_animation_controller_.SetHovered(true);
   ink_drop_animation_controller_.AnimateToState(InkDropState::ACTION_TRIGGERED);
+  test_api_.CompleteAnimations();
 
   EXPECT_TRUE(task_runner_->HasPendingTask());
 
   task_runner_->RunPendingTasks();
 
-  EXPECT_FALSE(is_hover_fading_in_or_visible());
+  EXPECT_FALSE(test_api_.IsHoverFadingInOrVisible());
 }
 
 TEST_F(InkDropAnimationControllerImplTest,
@@ -110,10 +108,11 @@
   ink_drop_host_.set_should_show_hover(true);
 
   ink_drop_animation_controller_.SetHovered(true);
-  EXPECT_TRUE(is_hover_fading_in_or_visible());
+  test_api_.CompleteAnimations();
+  EXPECT_TRUE(test_api_.IsHoverFadingInOrVisible());
 
   ink_drop_animation_controller_.AnimateToState(InkDropState::ACTION_TRIGGERED);
-  EXPECT_FALSE(is_hover_fading_in_or_visible());
+  EXPECT_FALSE(test_api_.IsHoverFadingInOrVisible());
 }
 
 // Verifies that there is not a crash when setting hovered state and the host
@@ -122,20 +121,21 @@
        SetHoveredFalseWorksWhenNoInkDropHoverExists) {
   ink_drop_host_.set_should_show_hover(false);
   ink_drop_animation_controller_.SetHovered(true);
-  EXPECT_FALSE(hover());
+  EXPECT_FALSE(test_api_.hover());
   ink_drop_animation_controller_.SetHovered(false);
-  EXPECT_FALSE(hover());
+  EXPECT_FALSE(test_api_.hover());
 }
 
 TEST_F(InkDropAnimationControllerImplTest, HoverFadesOutOnSnapToActivated) {
   ink_drop_host_.set_should_show_hover(true);
   ink_drop_animation_controller_.SetHovered(true);
+  test_api_.CompleteAnimations();
 
-  EXPECT_TRUE(is_hover_fading_in_or_visible());
+  EXPECT_TRUE(test_api_.IsHoverFadingInOrVisible());
 
   ink_drop_animation_controller_.SnapToActivated();
 
-  EXPECT_FALSE(is_hover_fading_in_or_visible());
+  EXPECT_FALSE(test_api_.IsHoverFadingInOrVisible());
 }
 
 }  // namespace views
diff --git a/ui/views/animation/ink_drop_animation_unittest.cc b/ui/views/animation/ink_drop_animation_unittest.cc
index d07b1c3..85434b5 100644
--- a/ui/views/animation/ink_drop_animation_unittest.cc
+++ b/ui/views/animation/ink_drop_animation_unittest.cc
@@ -69,7 +69,7 @@
     }
     case FLOOD_FILL_INK_DROP_ANIMATION: {
       FloodFillInkDropAnimation* flood_fill_ink_drop_animation =
-          new FloodFillInkDropAnimation(gfx::Size(10, 10), gfx::Point(),
+          new FloodFillInkDropAnimation(gfx::Rect(0, 0, 10, 10), gfx::Point(),
                                         SK_ColorBLACK);
       ink_drop_animation_.reset(flood_fill_ink_drop_animation);
       test_api_.reset(
diff --git a/ui/views/animation/ink_drop_hover.cc b/ui/views/animation/ink_drop_hover.cc
index 9bb7b02..f53a95a0 100644
--- a/ui/views/animation/ink_drop_hover.cc
+++ b/ui/views/animation/ink_drop_hover.cc
@@ -59,6 +59,10 @@
   AnimateFade(FADE_OUT, duration, size_, explode ? explode_size_ : size_);
 }
 
+test::InkDropHoverTestApi* InkDropHover::GetTestApi() {
+  return nullptr;
+}
+
 void InkDropHover::AnimateFade(HoverAnimationType animation_type,
                                const base::TimeDelta& duration,
                                const gfx::Size& initial_size,
diff --git a/ui/views/animation/ink_drop_hover.h b/ui/views/animation/ink_drop_hover.h
index b65f28a..cda2424 100644
--- a/ui/views/animation/ink_drop_hover.h
+++ b/ui/views/animation/ink_drop_hover.h
@@ -22,6 +22,10 @@
 }  // namespace ui
 
 namespace views {
+namespace test {
+class InkDropHoverTestApi;
+}  // namespace test
+
 class RoundedRectangleLayerDelegate;
 
 // Manages fade in/out animations for a painted Layer that is used to provide
@@ -32,7 +36,7 @@
                int corner_radius,
                const gfx::Point& center_point,
                SkColor color);
-  ~InkDropHover();
+  virtual ~InkDropHover();
 
   void set_explode_size(const gfx::Size& size) { explode_size_ = size; }
 
@@ -50,7 +54,14 @@
   // The root Layer that can be added in to a Layer tree.
   ui::Layer* layer() { return layer_.get(); }
 
+  // Returns a test api to access internals of this. Default implmentations
+  // should return nullptr and test specific subclasses can override to return
+  // an instance.
+  virtual test::InkDropHoverTestApi* GetTestApi();
+
  private:
+  friend class test::InkDropHoverTestApi;
+
   enum HoverAnimationType { FADE_IN, FADE_OUT };
 
   // Animates a fade in/out as specified by |animation_type| combined with a
diff --git a/ui/views/animation/test/ink_drop_animation_controller_impl_test_api.cc b/ui/views/animation/test/ink_drop_animation_controller_impl_test_api.cc
new file mode 100644
index 0000000..a41d67c
--- /dev/null
+++ b/ui/views/animation/test/ink_drop_animation_controller_impl_test_api.cc
@@ -0,0 +1,58 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/animation/test/ink_drop_animation_controller_impl_test_api.h"
+
+#include "ui/views/animation/ink_drop_animation.h"
+#include "ui/views/animation/ink_drop_animation_controller_impl.h"
+#include "ui/views/animation/ink_drop_hover.h"
+#include "ui/views/animation/test/ink_drop_animation_test_api.h"
+#include "ui/views/animation/test/ink_drop_hover_test_api.h"
+
+namespace views {
+namespace test {
+
+InkDropAnimationControllerImplTestApi::InkDropAnimationControllerImplTestApi(
+    InkDropAnimationControllerImpl* ink_drop_controller)
+    : ui::test::MultiLayerAnimatorTestController(this),
+      ink_drop_controller_(ink_drop_controller) {}
+
+InkDropAnimationControllerImplTestApi::
+    ~InkDropAnimationControllerImplTestApi() {}
+
+const InkDropHover* InkDropAnimationControllerImplTestApi::hover() const {
+  return ink_drop_controller_->hover_.get();
+}
+
+bool InkDropAnimationControllerImplTestApi::IsHoverFadingInOrVisible() const {
+  return ink_drop_controller_->IsHoverFadingInOrVisible();
+}
+
+std::vector<ui::LayerAnimator*>
+InkDropAnimationControllerImplTestApi::GetLayerAnimators() {
+  std::vector<ui::LayerAnimator*> animators;
+
+  if (ink_drop_controller_->hover_) {
+    InkDropHoverTestApi* ink_drop_hover_test_api =
+        ink_drop_controller_->hover_->GetTestApi();
+    std::vector<ui::LayerAnimator*> ink_drop_hover_animators =
+        ink_drop_hover_test_api->GetLayerAnimators();
+    animators.insert(animators.end(), ink_drop_hover_animators.begin(),
+                     ink_drop_hover_animators.end());
+  }
+
+  if (ink_drop_controller_->ink_drop_animation_) {
+    InkDropAnimationTestApi* ink_drop_animation_test_api =
+        ink_drop_controller_->ink_drop_animation_->GetTestApi();
+    std::vector<ui::LayerAnimator*> ink_drop_animation_animators =
+        ink_drop_animation_test_api->GetLayerAnimators();
+    animators.insert(animators.end(), ink_drop_animation_animators.begin(),
+                     ink_drop_animation_animators.end());
+  }
+
+  return animators;
+}
+
+}  // namespace test
+}  // namespace views
diff --git a/ui/views/animation/test/ink_drop_animation_controller_impl_test_api.h b/ui/views/animation/test/ink_drop_animation_controller_impl_test_api.h
new file mode 100644
index 0000000..54b80c6
--- /dev/null
+++ b/ui/views/animation/test/ink_drop_animation_controller_impl_test_api.h
@@ -0,0 +1,54 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_ANIMATION_TEST_INK_DROP_ANIMATION_CONTROLLER_IMPL_TEST_API_H_
+#define UI_VIEWS_ANIMATION_TEST_INK_DROP_ANIMATION_CONTROLLER_IMPL_TEST_API_H_
+
+#include <vector>
+
+#include "base/macros.h"
+#include "ui/compositor/test/multi_layer_animator_test_controller.h"
+#include "ui/compositor/test/multi_layer_animator_test_controller_delegate.h"
+
+namespace ui {
+class LayerAnimator;
+}  // namespace ui
+
+namespace views {
+class InkDropAnimationControllerImpl;
+class InkDropHover;
+
+namespace test {
+
+// Test API to provide internal access to an InkDropAnimationControllerImpl
+// instance. This can also be used to control the InkDropAnimation and
+// InkDropHover animations via the ui::test::MultiLayerAnimatorTestController
+// API.
+class InkDropAnimationControllerImplTestApi
+    : public ui::test::MultiLayerAnimatorTestController,
+      public ui::test::MultiLayerAnimatorTestControllerDelegate {
+ public:
+  explicit InkDropAnimationControllerImplTestApi(
+      InkDropAnimationControllerImpl* ink_drop_controller_);
+  ~InkDropAnimationControllerImplTestApi() override;
+
+  // Wrappers to InkDropAnimationControllerImpl internals:
+  const InkDropHover* hover() const;
+  bool IsHoverFadingInOrVisible() const;
+
+ protected:
+  // MultiLayerAnimatorTestControllerDelegate:
+  std::vector<ui::LayerAnimator*> GetLayerAnimators() override;
+
+ private:
+  // The InkDropedAnimation to provide internal access to.
+  InkDropAnimationControllerImpl* ink_drop_controller_;
+
+  DISALLOW_COPY_AND_ASSIGN(InkDropAnimationControllerImplTestApi);
+};
+
+}  // namespace test
+}  // namespace views
+
+#endif  // UI_VIEWS_ANIMATION_TEST_INK_DROP_ANIMATION_CONTROLLER_IMPL_TEST_API_H_
diff --git a/ui/views/animation/test/ink_drop_animation_test_api.h b/ui/views/animation/test/ink_drop_animation_test_api.h
index b8d44e4..611f3d7 100644
--- a/ui/views/animation/test/ink_drop_animation_test_api.h
+++ b/ui/views/animation/test/ink_drop_animation_test_api.h
@@ -21,8 +21,9 @@
 
 namespace test {
 
-// Base Test API used by test fixtures to validate all concrete implementations
-// of the InkDropAnimation class.
+// Test API to provide internal access to an InkDropAnimation instance. This can
+// also be used to control the animations via the
+// ui::test::MultiLayerAnimatorTestController API.
 class InkDropAnimationTestApi
     : public ui::test::MultiLayerAnimatorTestController,
       public ui::test::MultiLayerAnimatorTestControllerDelegate {
@@ -33,6 +34,9 @@
   // Gets the opacity of the ink drop.
   virtual float GetCurrentOpacity() const = 0;
 
+  // MultiLayerAnimatorTestControllerDelegate:
+  std::vector<ui::LayerAnimator*> GetLayerAnimators() override;
+
  protected:
   InkDropAnimation* ink_drop_animation() {
     return static_cast<const InkDropAnimationTestApi*>(this)
@@ -41,9 +45,6 @@
 
   InkDropAnimation* ink_drop_animation() const { return ink_drop_animation_; }
 
-  // MultiLayerAnimatorTestControllerDelegate:
-  std::vector<ui::LayerAnimator*> GetLayerAnimators() override;
-
  private:
   // The InkDropedAnimation to provide internal access to.
   InkDropAnimation* ink_drop_animation_;
diff --git a/ui/views/animation/test/ink_drop_hover_test_api.cc b/ui/views/animation/test/ink_drop_hover_test_api.cc
new file mode 100644
index 0000000..b7c1b45
--- /dev/null
+++ b/ui/views/animation/test/ink_drop_hover_test_api.cc
@@ -0,0 +1,29 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/animation/test/ink_drop_hover_test_api.h"
+
+#include "base/time/time.h"
+#include "ui/compositor/layer.h"
+#include "ui/compositor/layer_animator.h"
+#include "ui/compositor/test/layer_animator_test_controller.h"
+#include "ui/views/animation/ink_drop_hover.h"
+
+namespace views {
+namespace test {
+
+InkDropHoverTestApi::InkDropHoverTestApi(InkDropHover* ink_drop_hover)
+    : ui::test::MultiLayerAnimatorTestController(this),
+      ink_drop_hover_(ink_drop_hover) {}
+
+InkDropHoverTestApi::~InkDropHoverTestApi() {}
+
+std::vector<ui::LayerAnimator*> InkDropHoverTestApi::GetLayerAnimators() {
+  std::vector<ui::LayerAnimator*> animators;
+  animators.push_back(ink_drop_hover()->layer_->GetAnimator());
+  return animators;
+}
+
+}  // namespace test
+}  // namespace views
diff --git a/ui/views/animation/test/ink_drop_hover_test_api.h b/ui/views/animation/test/ink_drop_hover_test_api.h
new file mode 100644
index 0000000..07f24b5
--- /dev/null
+++ b/ui/views/animation/test/ink_drop_hover_test_api.h
@@ -0,0 +1,53 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_ANIMATION_TEST_INK_DROP_HOVER_TEST_API_H_
+#define UI_VIEWS_ANIMATION_TEST_INK_DROP_HOVER_TEST_API_H_
+
+#include <vector>
+
+#include "base/macros.h"
+#include "ui/compositor/test/multi_layer_animator_test_controller.h"
+#include "ui/compositor/test/multi_layer_animator_test_controller_delegate.h"
+
+namespace ui {
+class LayerAnimator;
+}  // namespace ui
+
+namespace views {
+class InkDropHover;
+
+namespace test {
+
+// Test API to provide internal access to an InkDropHover instance. This can
+// also be used to control the animations via the
+// ui::test::MultiLayerAnimatorTestController API.
+class InkDropHoverTestApi
+    : public ui::test::MultiLayerAnimatorTestController,
+      public ui::test::MultiLayerAnimatorTestControllerDelegate {
+ public:
+  explicit InkDropHoverTestApi(InkDropHover* ink_drop_hover);
+  ~InkDropHoverTestApi() override;
+
+  // MultiLayerAnimatorTestControllerDelegate:
+  std::vector<ui::LayerAnimator*> GetLayerAnimators() override;
+
+ protected:
+  InkDropHover* ink_drop_hover() {
+    return static_cast<const InkDropHoverTestApi*>(this)->ink_drop_hover();
+  }
+
+  InkDropHover* ink_drop_hover() const { return ink_drop_hover_; }
+
+ private:
+  // The InkDropedAnimation to provide internal access to.
+  InkDropHover* ink_drop_hover_;
+
+  DISALLOW_COPY_AND_ASSIGN(InkDropHoverTestApi);
+};
+
+}  // namespace test
+}  // namespace views
+
+#endif  // UI_VIEWS_ANIMATION_TEST_INK_DROP_HOVER_TEST_API_H_
diff --git a/ui/views/animation/test/test_ink_drop_host.cc b/ui/views/animation/test/test_ink_drop_host.cc
index c919b68..f264e25c 100644
--- a/ui/views/animation/test/test_ink_drop_host.cc
+++ b/ui/views/animation/test/test_ink_drop_host.cc
@@ -8,11 +8,74 @@
 #include "ui/gfx/geometry/size.h"
 #include "ui/views/animation/ink_drop_hover.h"
 #include "ui/views/animation/square_ink_drop_animation.h"
+#include "ui/views/animation/test/ink_drop_hover_test_api.h"
+#include "ui/views/animation/test/square_ink_drop_animation_test_api.h"
 
 namespace views {
 
+namespace {
+
+// Test specific subclass of InkDropAnimation that returns a test api from
+// GetTestApi().
+class TestInkDropAnimation : public SquareInkDropAnimation {
+ public:
+  TestInkDropAnimation(const gfx::Size& large_size,
+                       int large_corner_radius,
+                       const gfx::Size& small_size,
+                       int small_corner_radius,
+                       const gfx::Point& center_point,
+                       SkColor color)
+      : SquareInkDropAnimation(large_size,
+                               large_corner_radius,
+                               small_size,
+                               small_corner_radius,
+                               center_point,
+                               color) {}
+
+  ~TestInkDropAnimation() override {}
+
+  test::InkDropAnimationTestApi* GetTestApi() override {
+    if (!test_api_)
+      test_api_.reset(new test::SquareInkDropAnimationTestApi(this));
+    return test_api_.get();
+  }
+
+ private:
+  std::unique_ptr<test::InkDropAnimationTestApi> test_api_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestInkDropAnimation);
+};
+
+// Test specific subclass of InkDropHover that returns a test api from
+// GetTestApi().
+class TestInkDropHover : public InkDropHover {
+ public:
+  TestInkDropHover(const gfx::Size& size,
+                   int corner_radius,
+                   const gfx::Point& center_point,
+                   SkColor color)
+      : InkDropHover(size, corner_radius, center_point, color) {}
+
+  ~TestInkDropHover() override {}
+
+  test::InkDropHoverTestApi* GetTestApi() override {
+    if (!test_api_)
+      test_api_.reset(new test::InkDropHoverTestApi(this));
+    return test_api_.get();
+  }
+
+ private:
+  std::unique_ptr<test::InkDropHoverTestApi> test_api_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestInkDropHover);
+};
+
+}  // namespace
+
 TestInkDropHost::TestInkDropHost()
-    : num_ink_drop_layers_(0), should_show_hover_(false) {}
+    : num_ink_drop_layers_(0),
+      should_show_hover_(false),
+      disable_timers_for_test_(false) {}
 
 TestInkDropHost::~TestInkDropHost() {}
 
@@ -27,15 +90,22 @@
 std::unique_ptr<InkDropAnimation> TestInkDropHost::CreateInkDropAnimation()
     const {
   gfx::Size size(10, 10);
-  return base::WrapUnique(new SquareInkDropAnimation(
-      size, 5, size, 5, gfx::Point(), SK_ColorBLACK));
+  std::unique_ptr<InkDropAnimation> animation(
+      new TestInkDropAnimation(size, 5, size, 5, gfx::Point(), SK_ColorBLACK));
+  if (disable_timers_for_test_)
+    animation->GetTestApi()->SetDisableAnimationTimers(true);
+  return animation;
 }
 
 std::unique_ptr<InkDropHover> TestInkDropHost::CreateInkDropHover() const {
-  return should_show_hover_
-             ? base::WrapUnique(new InkDropHover(gfx::Size(10, 10), 4,
-                                                 gfx::Point(), SK_ColorBLACK))
-             : nullptr;
+  std::unique_ptr<InkDropHover> hover;
+  if (should_show_hover_) {
+    hover.reset(new TestInkDropHover(gfx::Size(10, 10), 4, gfx::Point(),
+                                     SK_ColorBLACK));
+    if (disable_timers_for_test_)
+      hover->GetTestApi()->SetDisableAnimationTimers(true);
+  }
+  return hover;
 }
 
 }  // namespace views
diff --git a/ui/views/animation/test/test_ink_drop_host.h b/ui/views/animation/test/test_ink_drop_host.h
index 5bf8650e..7bb18e1a 100644
--- a/ui/views/animation/test/test_ink_drop_host.h
+++ b/ui/views/animation/test/test_ink_drop_host.h
@@ -23,6 +23,10 @@
     should_show_hover_ = should_show_hover;
   }
 
+  void set_disable_timers_for_test(bool disable_timers_for_test) {
+    disable_timers_for_test_ = disable_timers_for_test;
+  }
+
   // TestInkDropHost:
   void AddInkDropLayer(ui::Layer* ink_drop_layer) override;
   void RemoveInkDropLayer(ui::Layer* ink_drop_layer) override;
@@ -34,6 +38,10 @@
 
   bool should_show_hover_;
 
+  // When true, the InkDropAnimation/InkDropHover instances will have their
+  // timers disabled after creation.
+  bool disable_timers_for_test_;
+
   DISALLOW_COPY_AND_ASSIGN(TestInkDropHost);
 };
 
diff --git a/ui/views/controls/button/label_button.cc b/ui/views/controls/button/label_button.cc
index 19dbb5be..f2371ea 100644
--- a/ui/views/controls/button/label_button.cc
+++ b/ui/views/controls/button/label_button.cc
@@ -424,7 +424,8 @@
   return GetText().empty()
              ? CustomButton::CreateInkDropAnimation()
              : base::WrapUnique(new views::FloodFillInkDropAnimation(
-                   size(), GetInkDropCenter(), GetInkDropBaseColor()));
+                   GetLocalBounds(), GetInkDropCenter(),
+                   GetInkDropBaseColor()));
 }
 
 std::unique_ptr<views::InkDropHover> LabelButton::CreateInkDropHover() const {
diff --git a/ui/views/views.gyp b/ui/views/views.gyp
index 1703707..d158ba5 100644
--- a/ui/views/views.gyp
+++ b/ui/views/views.gyp
@@ -494,6 +494,10 @@
       'animation/test/flood_fill_ink_drop_animation_test_api.h',
       'animation/test/ink_drop_animation_test_api.cc',
       'animation/test/ink_drop_animation_test_api.h',
+      'animation/test/ink_drop_animation_controller_impl_test_api.cc',
+      'animation/test/ink_drop_animation_controller_impl_test_api.h',
+      'animation/test/ink_drop_hover_test_api.cc',
+      'animation/test/ink_drop_hover_test_api.h',
       'animation/test/square_ink_drop_animation_test_api.cc',
       'animation/test/square_ink_drop_animation_test_api.h',
       'animation/test/test_ink_drop_animation_observer.cc',